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,3099 @@
1
+ # TODO finish clean the code manually too many comments
2
+ from batoolset.settings.global_settings import set_UI # set the UI to qtpy
3
+ set_UI()# TODO --> get started
4
+ import os
5
+ import traceback
6
+ import matplotlib.pyplot as plt
7
+ from qtpy.QtWidgets import QApplication
8
+ from numba import njit, jit
9
+ from batoolset.img import Img, RGB_to_int24, int24_to_RGB
10
+ from batoolset.ta.tracking.rapid_detection_of_vertices import neighbors8
11
+ from batoolset.tools.early_stopper_class import early_stop
12
+ from batoolset.utils.loadlist import loadlist
13
+ # from personal.pyTA.tracking.rapid_detection_of_vertices import _cantor_pairing
14
+ from batoolset.colors.colorgen import r_g_b_from_rgb, r_g_b_to_rgb
15
+ from batoolset.GUI.multi_image_display import ImgDisplayWindow
16
+ from batoolset.luts.lut_minimal_test import apply_lut, matplotlib_to_TA
17
+ from batoolset.files.tools import get_n_files_from_list, smart_name_parser
18
+ from timeit import default_timer as timer
19
+ import numpy as np
20
+ from skimage.measure import label, regionprops
21
+ import operator
22
+
23
+ # TODO --> really test the signatures of njit just to see
24
+
25
+ USE_NUMBA = True # ça a pas l'air de marcher ou je comprend pas --> check --> maybe check nopython in jit
26
+ FIX_SWAPS = True
27
+
28
+ @njit
29
+ def get_vx_neighbors(vertices_coords, RGB24img):
30
+ """
31
+ Get the neighbors of each vertex.
32
+
33
+ Args:
34
+ vertices_coords (numpy.ndarray): Array of vertex coordinates.
35
+ RGB24img (numpy.ndarray): RGB image.
36
+
37
+ Returns:
38
+ list: List of neighbor colors for each vertex.
39
+
40
+ """
41
+ neighbors = []
42
+
43
+ for iii in range(vertices_coords.shape[0]):
44
+ i = int(vertices_coords[iii, 1])
45
+ j = int(vertices_coords[iii, 0])
46
+
47
+ neighbours8 = RGB24img[j - 1:j + 2, i - 1:i + 2]
48
+ neighbs = []
49
+ for neighbor in neighbours8.ravel():
50
+ if neighbor != 0xFFFFFF:
51
+ neighbs.append(neighbor)
52
+ neighbors.append(neighbs)
53
+
54
+ return neighbors
55
+
56
+
57
+ def find_best_matches_both_ways(img_t_cur, img_t_another, translation=None):
58
+ """
59
+ Find the best matches between two images in both directions.
60
+
61
+ Args:
62
+ img_t_cur (numpy.ndarray): Image at time t_cur.
63
+ img_t_another (numpy.ndarray): Image at another time.
64
+ translation (None, optional): Translation parameters. Defaults to None.
65
+
66
+ Returns:
67
+ dict: Best matches between colors in img_t_cur and img_t_another.
68
+
69
+ """
70
+ match_t_cur_in_t_prev = {}
71
+ match_t_prev_in_t_cur = {}
72
+
73
+ for j in range(1, img_t_cur.shape[0] - 1):
74
+ for i in range(1, img_t_cur.shape[1] - 1):
75
+ cur_col = img_t_cur[j, i]
76
+ if cur_col != 0xFFFFFF:
77
+ col_in_other_image = img_t_another[j, i]
78
+ if col_in_other_image != 0xFFFFFF:
79
+ if cur_col in match_t_cur_in_t_prev.keys():
80
+ match_t_cur_in_t_prev[cur_col].append(col_in_other_image)
81
+ else:
82
+ match_t_cur_in_t_prev[cur_col] = [col_in_other_image]
83
+
84
+ # Rest of the code is not provided, please complete it if needed
85
+
86
+ return match_t_cur_in_t_prev
87
+ # print(match_t_cur_in_t_prev)
88
+
89
+
90
+ @njit
91
+ def find_vertices(RGB24img, return_vertices=True, return_bonds=False):
92
+ """
93
+ Find vertices in the RGB image.
94
+
95
+ Args:
96
+ RGB24img (numpy.ndarray): RGB image.
97
+ return_vertices (bool, optional): Whether to return vertices. Defaults to True.
98
+ return_bonds (bool, optional): Whether to return bonds. Defaults to False.
99
+
100
+ Returns:
101
+ numpy.ndarray or tuple: Vertices or vertices and bonds.
102
+
103
+ """
104
+ vertices = [(0, 0)]
105
+ vertices.clear()
106
+ bonds = np.zeros_like(RGB24img)
107
+
108
+ for j in range(1, RGB24img.shape[0] - 1):
109
+ for i in range(1, RGB24img.shape[1] - 1):
110
+ if RGB24img[j, i] == 0xFFFFFF:
111
+ neighbours8 = RGB24img[j - 1:j + 2, i - 1:i + 2]
112
+ neighbour_count = np.unique(neighbours8).size
113
+
114
+ if neighbour_count >= 4:
115
+ vertices.append((j, i))
116
+
117
+ if neighbour_count == 3:
118
+ id1 = None
119
+ id2 = None
120
+ for neighbour in neighbours8.ravel():
121
+ if neighbour != 0xFFFFFF:
122
+ if id1 is None:
123
+ id1 = neighbour
124
+ elif id2 is None and neighbour != id1:
125
+ id2 = neighbour
126
+ break
127
+
128
+ id = _cantor_pairing(id1, id2) # Bug in the mapping or int32 conversion, ignore for now
129
+
130
+ bonds[j, i] = id
131
+
132
+ if return_bonds:
133
+ return bonds.astype(np.uint64)
134
+
135
+ return np.asarray(vertices).astype(np.uint64)
136
+
137
+
138
+ @njit
139
+ def find_vertices2(RGB24img):
140
+ """
141
+ Find vertices in the RGB image.
142
+
143
+ Args:
144
+ RGB24img (numpy.ndarray): RGB image.
145
+
146
+ Returns:
147
+ numpy.ndarray: Vertices with white pixels marked as 255.
148
+
149
+ """
150
+ vertices = np.zeros_like(RGB24img)
151
+
152
+ for j in range(1, RGB24img.shape[0] - 1):
153
+ for i in range(1, RGB24img.shape[1] - 1):
154
+ if RGB24img[j, i] == 0xFFFFFF:
155
+ neighbours8 = RGB24img[j - 1:j + 2, i - 1:i + 2]
156
+ neighbour_count = len(np.unique(neighbours8))
157
+
158
+ if neighbour_count >= 4:
159
+ vertices[j, i] = 255
160
+
161
+ return vertices
162
+
163
+
164
+ @njit
165
+ def _cantor_pairing2(id1, id2, _sort_points=True, cantor_mapping=None):
166
+ """
167
+ Perform Cantor pairing of two IDs.
168
+
169
+ Args:
170
+ id1: First ID.
171
+ id2: Second ID.
172
+ _sort_points (bool, optional): Whether to sort the points. Defaults to True.
173
+ cantor_mapping (dict, optional): Mapping for Cantor IDs. Defaults to None.
174
+
175
+ Returns:
176
+ int: Cantor pairing result.
177
+
178
+ """
179
+ x = id1
180
+ y = id2
181
+ if _sort_points and id1 < id2:
182
+ x = id2
183
+ y = id1
184
+ cantor_id = (((x + y) * (x + y + 1.) / 2.) + y)
185
+ if cantor_mapping is not None:
186
+ if cantor_id in cantor_mapping:
187
+ return cantor_mapping[cantor_id]
188
+ else:
189
+ simple_id = len(cantor_mapping) + 1
190
+ cantor_mapping[cantor_id] = simple_id
191
+ return simple_id
192
+ return cantor_id
193
+
194
+
195
+ @njit
196
+ def _cantor_pairing(id1, id2, _sort_points=True):
197
+ """
198
+ Perform Cantor pairing of two IDs.
199
+
200
+ Args:
201
+ id1: First ID.
202
+ id2: Second ID.
203
+ _sort_points (bool, optional): Whether to sort the points. Defaults to True.
204
+
205
+ Returns:
206
+ int: Cantor pairing result.
207
+
208
+ """
209
+ x = id1
210
+ y = id2
211
+ if _sort_points and id1 < id2:
212
+ x = id2
213
+ y = id1
214
+ return int(((x + y) * (x + y + 1) / 2) + y)
215
+
216
+
217
+ @njit
218
+ def associate_cell_to_its_neighbors2(vertices_coords, RGB24img, bg_color=0xFFFFFF):
219
+ """
220
+ Associate cells to their neighbors based on vertices.
221
+
222
+ Args:
223
+ vertices_coords (numpy.ndarray): Coordinates of the vertices.
224
+ RGB24img (numpy.ndarray): RGB image.
225
+ bg_color (int, optional): Background color. Defaults to 0xFFFFFF.
226
+
227
+ Returns:
228
+ list: List of pairs representing the neighbors.
229
+
230
+ """
231
+ pairs = [(0, 0)]
232
+ pairs.clear()
233
+
234
+ for iii in range(vertices_coords.shape[0]):
235
+ i = int(vertices_coords[iii, 1])
236
+ j = int(vertices_coords[iii, 0])
237
+
238
+ min_y = j - 1
239
+ max_y = j + 2
240
+ min_x = i - 1
241
+ max_x = i + 2
242
+ min_y = min_y if min_y >= 0 else 0
243
+ max_y = max_y if max_y < RGB24img.shape[0] else RGB24img.shape[0]
244
+ min_x = min_x if min_x >= 0 else 0
245
+ max_x = max_x if max_x < RGB24img.shape[1] else RGB24img.shape[1]
246
+ neighbours8 = RGB24img[min_y:max_y, min_x:max_x]
247
+
248
+ neighbours82 = np.unique(neighbours8.ravel())
249
+
250
+ for iii, id1 in enumerate(neighbours82):
251
+ if id1 != bg_color:
252
+ for jjj in range(iii + 1, len(neighbours82)):
253
+ id2 = neighbours82[jjj]
254
+ if id2 != bg_color:
255
+ pairs.append((id1, id2))
256
+ pairs.append((id2, id1))
257
+
258
+ return pairs
259
+
260
+
261
+ @njit
262
+ def associate_cell_to_its_neighbors(RGB24img):
263
+ """
264
+ Associate cells to their neighbors.
265
+
266
+ Args:
267
+ RGB24img (numpy.ndarray): RGB image.
268
+
269
+ Returns:
270
+ list: List of pairs representing the neighbors.
271
+
272
+ """
273
+ pairs = [(0, 0)]
274
+ pairs.clear()
275
+
276
+ for j in range(1, RGB24img.shape[0] - 1):
277
+ for i in range(1, RGB24img.shape[1] - 1):
278
+ if RGB24img[j, i] == 0xFFFFFF:
279
+ neighbours8 = RGB24img[j - 1:j + 2, i - 1:i + 2]
280
+ neighbour_count = len(np.unique(neighbours8))
281
+
282
+ if neighbour_count == 3:
283
+ id1 = None
284
+ id2 = None
285
+ for neighbour in neighbours8.ravel():
286
+ if neighbour != 0xFFFFFF:
287
+ if id1 is None:
288
+ id1 = neighbour
289
+ elif id2 is None and neighbour != id1:
290
+ id2 = neighbour
291
+ break
292
+
293
+ pairs.append((id1, id2))
294
+ pairs.append((id2, id1))
295
+
296
+ return pairs
297
+
298
+ @njit
299
+ def find_bonds(RGB24img):
300
+ bonds = np.zeros_like(RGB24img)
301
+
302
+ for j in range(1, RGB24img.shape[0] - 1):
303
+ for i in range(1, RGB24img.shape[1] - 1):
304
+ if RGB24img[j, i] == 0xFFFFFF:
305
+ neighbours8 = RGB24img[j - 1:j + 2, i - 1:i + 2]
306
+ neighbour_count = len(np.unique(neighbours8))
307
+
308
+ if neighbour_count == 3:
309
+ id1 = None
310
+ id2 = None
311
+ for neighbour in neighbours8.ravel():
312
+ if neighbour != 0xFFFFFF:
313
+ if id1 is None:
314
+ id1 = neighbour
315
+ elif id2 is None and neighbour != id1:
316
+ id2 = neighbour
317
+ break
318
+
319
+ id = _cantor_pairing(id1, id2)
320
+ bonds[j, i] = id
321
+
322
+ return bonds
323
+
324
+
325
+ def find_neighbors_to_check(cell_of_interest_in_cur, cells_and_their_neighbors_t_cur,
326
+ cells_and_their_neighbors_t_other):
327
+ """
328
+ Finds the neighbors to check for potential swaps or assignments.
329
+
330
+ Args:
331
+ cell_of_interest_in_cur: The cell of interest in the current time frame.
332
+ cells_and_their_neighbors_t_cur (dict): Dictionary mapping cells to their neighbors in the current time frame.
333
+ cells_and_their_neighbors_t_other (dict): Dictionary mapping cells to their neighbors in another time frame.
334
+
335
+ Returns:
336
+ tuple: A tuple containing two lists - possible_swaps and possible_assignments.
337
+
338
+ """
339
+ neighbs_to_check = []
340
+ neighbs_of_cell_of_interest_in_t_cur = cells_and_their_neighbors_t_cur[cell_of_interest_in_cur]
341
+
342
+ for neighb_of_cell_of_interest_in_t_cur in neighbs_of_cell_of_interest_in_t_cur:
343
+ if neighb_of_cell_of_interest_in_t_cur in cells_and_their_neighbors_t_other.keys():
344
+ neighbours_of_neighbs_in_t_other = cells_and_their_neighbors_t_other[neighb_of_cell_of_interest_in_t_cur]
345
+ for neighbour_of_neighbs_in_t_other in neighbours_of_neighbs_in_t_other:
346
+ neighbs_to_check.append(neighbour_of_neighbs_in_t_other)
347
+
348
+ neighbs_to_check.extend(neighbs_of_cell_of_interest_in_t_cur)
349
+ neighbs_to_check = set(neighbs_to_check)
350
+ if cell_of_interest_in_cur in neighbs_to_check:
351
+ neighbs_to_check.remove(cell_of_interest_in_cur)
352
+ neighbs_to_check = list(neighbs_to_check)
353
+
354
+ possible_swaps = [id for id in neighbs_to_check if id in cells_and_their_neighbors_t_cur.keys()]
355
+ possible_assignments = [id for id in neighbs_to_check if id not in cells_and_their_neighbors_t_cur.keys()]
356
+
357
+ return possible_swaps, possible_assignments
358
+
359
+
360
+ @jit(nopython=True)
361
+ def find_first(item, vec):
362
+ """
363
+ Finds the index of the first occurrence of an item in a vector.
364
+
365
+ Args:
366
+ item: The item to find.
367
+ vec: The vector to search.
368
+
369
+ Returns:
370
+ int: The index of the first occurrence of the item, or -1 if not found.
371
+
372
+ """
373
+ for i in range(len(vec)):
374
+ if item == vec[i]:
375
+ return i
376
+ return -1
377
+
378
+ def plot_n_images_in_line(*args, title=None):
379
+ """
380
+ Plots multiple images in a single line.
381
+
382
+ Args:
383
+ *args: Variable length argument list of images to plot.
384
+ title (str): Optional title for the plot.
385
+
386
+ """
387
+ nb_images = len(args)
388
+ f, axarr = plt.subplots(ncols=nb_images, sharex=True, sharey=True)
389
+
390
+ for iii, img in enumerate(args):
391
+ axarr[iii].imshow(img)
392
+
393
+ f.subplots_adjust(0, 0, 1, 1)
394
+ plt.tight_layout()
395
+
396
+ full_screen = True
397
+ if full_screen:
398
+ manager = plt.get_current_fig_manager()
399
+ manager.window.showMaximized()
400
+
401
+ hide_white_space = True
402
+ if hide_white_space:
403
+ plt.subplots_adjust(wspace=0, hspace=0, left=0, right=1, bottom=0, top=1)
404
+
405
+ if title is not None:
406
+ plt.title(title)
407
+
408
+ plt.show()
409
+
410
+
411
+ def associate_cells_to_neighbors_ID_in_dict(cells_and_their_neighbors_cur):
412
+ """
413
+ Associates cells to their neighbor IDs in a dictionary.
414
+
415
+ Args:
416
+ cells_and_their_neighbors_cur (dict): Dictionary mapping cells to their neighbor IDs.
417
+
418
+ Returns:
419
+ dict: Dictionary mapping cells to lists of their neighbor IDs.
420
+
421
+ """
422
+ cells_and_their_neighbs = {}
423
+
424
+ for id, neighb in cells_and_their_neighbors_cur:
425
+ if id in cells_and_their_neighbs:
426
+ cells_and_their_neighbs[id].append(neighb)
427
+ else:
428
+ cells_and_their_neighbs[id] = [neighb]
429
+
430
+ return cells_and_their_neighbs
431
+
432
+
433
+ overseg = 'overseg'
434
+ underseg = 'underseg'
435
+ division = 'division'
436
+ death = 'death'
437
+ gone = 'gone' # can be out of focus and in that case should really not be labelled as death # same as death but unlabeled as a solution --> is that useful or not (can be a delaminating cell, practically it's the same as death isn't it --> do I need to complicate things ??? --> probably not)
438
+ new = 'new'
439
+ swapped = 'swapped'
440
+ lost_track = 'lost_track'
441
+ ignore = 'ignore' # cell is perfect no action required
442
+ # NB DIVISION COULD BE TRANSFORMED INTO INTERCALATING IF A DIVISION PARTNER CANNOT BE FOUND OR IF AREA IS VERY LOW INITIALLY FOR THE NEW CELL --> IN FACT I HAVE NEW SO I DON'T NEED INTERCALATING --> BECAUSE IT'S REDUNDANT
443
+
444
+ fates = [overseg, underseg, division, death, new, swapped, lost_track,
445
+ ignore] # can there be other fates # there must be rules depending on the stuff
446
+
447
+
448
+ def take_decision(cell_of_interest_in_cur, cells_and_their_neighbors_minus_1, cells_and_their_neighbors_cur,
449
+ cells_and_their_neighbors_plus_1, cells_present_in_t_cur_but_absent_in_t_minus_1_score,
450
+ cells_present_in_t_cur_but_absent_in_t_plus_1_score, sensitivity=0.75,
451
+ assume_previous_image_is_GT=True):
452
+ """
453
+ Takes a decision about a cell based on its presence in different frames and neighbor information.
454
+
455
+ Args:
456
+ cell_of_interest_in_cur: Cell of interest in the current frame.
457
+ cells_and_their_neighbors_minus_1: Dictionary mapping cells to their neighbors in the previous frame.
458
+ cells_and_their_neighbors_cur: Dictionary mapping cells to their neighbors in the current frame.
459
+ cells_and_their_neighbors_plus_1: Dictionary mapping cells to their neighbors in the next frame.
460
+ cells_present_in_t_cur_but_absent_in_t_minus_1_score: Scores indicating the presence of cells in the current
461
+ frame but absent in the previous frame.
462
+ cells_present_in_t_cur_but_absent_in_t_plus_1_score: Scores indicating the presence of cells in the current
463
+ frame but absent in the next frame.
464
+ sensitivity (float): Sensitivity threshold for considering neighbor changes significant. Default is 0.75.
465
+ assume_previous_image_is_GT (bool): Flag indicating whether to assume the previous image as the ground truth.
466
+ Default is True.
467
+
468
+ Returns:
469
+ list: List of possible decisions for the cell.
470
+
471
+ """
472
+ # TODO add lost_track in some cases
473
+
474
+ # case 1: cell is missing in the previous frame
475
+ if cell_of_interest_in_cur not in cells_and_their_neighbors_minus_1.keys():
476
+ if assume_previous_image_is_GT:
477
+ # check if missing cell is in the next frame
478
+ if cell_of_interest_in_cur in cells_and_their_neighbors_plus_1.keys():
479
+ # assume it is a division
480
+ return ['division', 'new']
481
+ else:
482
+ return ['overseg']
483
+ else:
484
+ possibilities = ['underseg-1', 'division', 'overseg', 'new']
485
+ if cell_of_interest_in_cur not in cells_and_their_neighbors_plus_1.keys():
486
+ possibilities.remove('division')
487
+ possibilities.remove('new')
488
+ return possibilities
489
+
490
+ # case 2: cell is missing in the next frame
491
+ if cell_of_interest_in_cur not in cells_and_their_neighbors_plus_1.keys():
492
+ if cell_of_interest_in_cur in cells_and_their_neighbors_minus_1.keys():
493
+ # cell was present before, likely a dying cell or an overseg
494
+ return ['death', 'gone', 'underseg+1']
495
+ else:
496
+ return ['overseg']
497
+
498
+ # cell is present in all frames, but its score is suboptimal
499
+ # check if score is 1 in both previous and next frames, ignore the cell
500
+ if cells_present_in_t_cur_but_absent_in_t_minus_1_score[cell_of_interest_in_cur] == 1 and \
501
+ cells_present_in_t_cur_but_absent_in_t_plus_1_score[cell_of_interest_in_cur] == 1:
502
+ return ['ignore']
503
+
504
+ if sensitivity is not None:
505
+ if cells_present_in_t_cur_but_absent_in_t_minus_1_score[cell_of_interest_in_cur] >= sensitivity and \
506
+ cells_present_in_t_cur_but_absent_in_t_plus_1_score[cell_of_interest_in_cur] >= sensitivity:
507
+ # cell most likely has changed one or two neighbors, no reason to worry
508
+ return ['ignore']
509
+
510
+ # now some of those cells may be swapped, fix them
511
+
512
+ # cell score is below the threshold, needs attention
513
+ # if score has significantly decreased compared to the previous frame, may be an underseg or swapping
514
+ # check for missing or gained cells in the previous and next frames to determine if it's overseg or not
515
+ # not easy to determine, center on the problematic cells
516
+
517
+ # case 3: missing cell in the current frame, absent in the previous frame (which is GT)
518
+ # either a division or an overseg
519
+ # if the cell is also absent in the next frame, it's for sure an overseg
520
+ # offer the possibility to discard
521
+ # offer several possibilities according to rules
522
+
523
+ pass
524
+
525
+
526
+ def get_cells_in_image_n_fisrt_pixel(RGB24_img, return_flat_idx=False):
527
+ """
528
+ Retrieves the cells in the image and their first pixel indices.
529
+
530
+ Args:
531
+ RGB24_img (ndarray): RGB image.
532
+ return_flat_idx (bool): Flag indicating whether to return the flat indices or 2D indices. Default is False.
533
+
534
+ Returns:
535
+ tuple: A tuple containing unique cell values and their corresponding indices.
536
+
537
+ """
538
+ u, indices = np.unique(RGB24_img, return_index=True)
539
+
540
+ if not return_flat_idx:
541
+ indices = np.unravel_index(indices, RGB24_img.shape)
542
+
543
+ return u, indices
544
+
545
+
546
+ def apply_color_to_labels(lab_t_cur, map_tracks_n_label_t_cur):
547
+ """
548
+ Applies color mapping to the label image.
549
+
550
+ Args:
551
+ lab_t_cur (ndarray): Label image.
552
+ map_tracks_n_label_t_cur (dict): Mapping of tracks to label values.
553
+
554
+ Returns:
555
+ ndarray: Updated label image with applied color mapping.
556
+
557
+ """
558
+ tracked_cells = np.zeros_like(lab_t_cur)
559
+
560
+ for k, v in map_tracks_n_label_t_cur:
561
+ tracked_cells[lab_t_cur == v] = k
562
+
563
+ return tracked_cells
564
+
565
+ def map_track_id_to_label(first_pixels_t_cur, track_t_cur, lab_t_cur):
566
+ """
567
+ Maps the track IDs to their corresponding labels based on the first pixels of each cell.
568
+
569
+ Args:
570
+ first_pixels_t_cur (tuple): Tuple of arrays representing the first pixels of each cell.
571
+ track_t_cur (ndarray): Array representing the tracks of cells.
572
+ lab_t_cur (ndarray): Array representing the labels of cells.
573
+
574
+ Returns:
575
+ ndarray: Array containing the mapping of track IDs to labels.
576
+ """
577
+ map = []
578
+ for j, i in zip(*first_pixels_t_cur):
579
+ map.append((track_t_cur[j, i], lab_t_cur[j, i]))
580
+ return np.asarray(map)
581
+
582
+
583
+ def compute_neighbor_score(cells_and_their_neighbors_cur, cells_and_their_neighbors_t_other,
584
+ cells_present_in_t_cur_but_absent_in_t_other=None,
585
+ cells_present_in_t_cur_but_absent_in_t_other_score=None, score_plotting_image=None,
586
+ track_t_cur=None):
587
+ """
588
+ Computes the neighbor score between cells in the current frame and cells in another frame.
589
+
590
+ Args:
591
+ cells_and_their_neighbors_cur (dict): Dictionary containing the cells in the current frame and their neighbors.
592
+ cells_and_their_neighbors_t_other (dict): Dictionary containing the cells in another frame and their neighbors.
593
+ cells_present_in_t_cur_but_absent_in_t_other (list, optional): List to store cells present in the current frame but absent in the other frame. Defaults to None.
594
+ cells_present_in_t_cur_but_absent_in_t_other_score (dict, optional): Dictionary to store the neighbor scores of cells present in the current frame but absent in the other frame. Defaults to None.
595
+ score_plotting_image (ndarray, optional): Array to plot the computed scores. Defaults to None.
596
+ track_t_cur (ndarray, optional): Array representing the tracks of cells in the current frame. Defaults to None.
597
+
598
+ Returns:
599
+ float: Sum of the neighbor scores.
600
+ """
601
+ sum_score = 0
602
+ for cell, neigbs in cells_and_their_neighbors_cur.items():
603
+ if cell in cells_and_their_neighbors_t_other.keys():
604
+ neigbsb = cells_and_their_neighbors_t_other[cell]
605
+ score = pairwise_score(neigbs, neigbsb)
606
+ sum_score += score
607
+ if cells_present_in_t_cur_but_absent_in_t_other_score is not None:
608
+ cells_present_in_t_cur_but_absent_in_t_other_score[cell] = score
609
+ if score_plotting_image is not None and track_t_cur is not None:
610
+ score_plotting_image[track_t_cur == cell] = score
611
+ else:
612
+ if cells_present_in_t_cur_but_absent_in_t_other is not None:
613
+ cells_present_in_t_cur_but_absent_in_t_other.append(cell)
614
+ if cells_present_in_t_cur_but_absent_in_t_other_score is not None:
615
+ cells_present_in_t_cur_but_absent_in_t_other_score[cell] = 0
616
+ return sum_score
617
+
618
+
619
+ def pairwise_score(neigbs, neigbsb):
620
+ """
621
+ Computes the pairwise score between two sets of neighbors.
622
+
623
+ Args:
624
+ neigbs (list): List of neighbors for the first set of cells.
625
+ neigbsb (list): List of neighbors for the second set of cells.
626
+
627
+ Returns:
628
+ float: Pairwise score between the two sets of neighbors.
629
+ """
630
+ score = (len(set(neigbs) & set(neigbsb)) * 2) / (len(neigbs) + len(neigbsb))
631
+ return score
632
+
633
+
634
+ def get_cells_and_their_neighbors_from_image(img, vertices=None, bg_color=0xFFFFFF):
635
+ """
636
+ Retrieves the cells and their neighbors from an image.
637
+
638
+ Args:
639
+ img (ndarray): Array representing the image.
640
+ vertices (ndarray, optional): Array containing the vertices of the cells. Defaults to None.
641
+ bg_color (int, optional): Background color of the image. Defaults to 0xFFFFFF.
642
+
643
+ Returns:
644
+ dict: Dictionary containing the cells and their neighbors.
645
+ """
646
+ if len(img.shape) == 3:
647
+ tmp = RGB_to_int24(img)
648
+ else:
649
+ tmp = img
650
+
651
+ if vertices is None:
652
+ vertices = np.stack(np.where(tmp == bg_color), axis=1)
653
+
654
+ cells_and_their_neighbors = np.unique(
655
+ np.asarray(associate_cell_to_its_neighbors2(vertices, tmp, bg_color=bg_color)), axis=0)
656
+ cells_and_their_neighbors = associate_cells_to_neighbors_ID_in_dict(cells_and_their_neighbors)
657
+ return cells_and_their_neighbors
658
+
659
+
660
+ def detect_divisions(cells_and_their_neighbors_cur, cells_and_their_neighbors_t_minus_1,
661
+ cells_and_their_neighbors_t_plus_1=None):
662
+ """
663
+ Detects cell divisions based on the cells and their neighbors in different frames.
664
+
665
+ Args:
666
+ cells_and_their_neighbors_cur (dict or ndarray): Dictionary or array containing the cells and their neighbors in the current frame.
667
+ cells_and_their_neighbors_t_minus_1 (dict or ndarray): Dictionary or array containing the cells and their neighbors in the previous frame.
668
+ cells_and_their_neighbors_t_plus_1 (dict or ndarray, optional): Dictionary or array containing the cells and their neighbors in the next frame. Defaults to None.
669
+
670
+ Returns:
671
+ dict: Dictionary containing the dividing pairs of cells.
672
+ """
673
+ dividing_pairs = {}
674
+
675
+ if isinstance(cells_and_their_neighbors_cur, np.ndarray):
676
+ cells_and_their_neighbors_cur = get_cells_and_their_neighbors_from_image(cells_and_their_neighbors_cur)
677
+ if isinstance(cells_and_their_neighbors_t_minus_1, np.ndarray):
678
+ cells_and_their_neighbors_t_minus_1 = get_cells_and_their_neighbors_from_image(
679
+ cells_and_their_neighbors_t_minus_1)
680
+ if isinstance(cells_and_their_neighbors_t_plus_1, np.ndarray):
681
+ cells_and_their_neighbors_t_plus_1 = get_cells_and_their_neighbors_from_image(
682
+ cells_and_their_neighbors_t_plus_1)
683
+
684
+ new_cells_in_t_cur = set(cells_and_their_neighbors_cur.keys()) - set(cells_and_their_neighbors_t_minus_1.keys())
685
+ if cells_and_their_neighbors_t_plus_1 is not None:
686
+ new_cells_in_t_cur = new_cells_in_t_cur & set(cells_and_their_neighbors_t_plus_1.keys())
687
+
688
+ for cell in new_cells_in_t_cur:
689
+ max_score = 0
690
+ neighbs_current_cell = cells_and_their_neighbors_cur[cell]
691
+ for possible_sister in neighbs_current_cell:
692
+ if possible_sister not in cells_and_their_neighbors_t_minus_1.keys():
693
+ continue
694
+ possible_sister_neighbors = cells_and_their_neighbors_t_minus_1[possible_sister]
695
+ merged_set = list(possible_sister_neighbors)
696
+ merged_set.extend(neighbs_current_cell)
697
+ merged_set = list(set(merged_set))
698
+ neighbs_in_previous_image = cells_and_their_neighbors_t_minus_1[possible_sister]
699
+ score = pairwise_score(neighbs_in_previous_image, merged_set)
700
+ if score > max_score:
701
+ max_score = score
702
+ dividing_pairs[cell] = possible_sister
703
+
704
+ return dividing_pairs
705
+
706
+ def get_border_cells_plus_one(cells_n_their_neighbors, border_cells, forbidden_ids=[0xFFFFFF], remove_border_cells=False):
707
+ """
708
+ Retrieves the border cells plus one layer of neighbors.
709
+
710
+ Args:
711
+ cells_n_their_neighbors (dict): Dictionary containing the cells and their neighbors.
712
+ border_cells (list): List of border cells.
713
+ forbidden_ids (list, optional): List of forbidden cell IDs. Defaults to [0xFFFFFF].
714
+ remove_border_cells (bool, optional): Whether to remove border cells from the result. Defaults to False.
715
+
716
+ Returns:
717
+ list: List of border cells plus one layer of neighbors.
718
+ """
719
+ border_cells_plus_one = []
720
+ for border_cell in border_cells:
721
+ try:
722
+ border_cells_plus_one.extend(cells_n_their_neighbors[border_cell])
723
+ except:
724
+ pass
725
+ if forbidden_ids is not None:
726
+ border_cells_plus_one = list(set(border_cells_plus_one)-set(forbidden_ids))
727
+ else:
728
+ border_cells_plus_one = list(set(border_cells_plus_one))
729
+ if remove_border_cells:
730
+ border_cells_plus_one = list(set(border_cells_plus_one)-set(border_cells))
731
+ return border_cells_plus_one
732
+
733
+
734
+ def plot_anything_a_la_TA(cell_id, list_of_cells_to_plot, color=0xFF0000, keep_mask=True):
735
+ """
736
+ Generates an image where specific cells are colored.
737
+
738
+ Args:
739
+ cell_id (ndarray): Array representing the cell IDs.
740
+ list_of_cells_to_plot (list): List of cells to be colored.
741
+ color (int, optional): Color to be used for coloring the cells. Defaults to 0xFF0000.
742
+ keep_mask (bool, optional): Whether to keep the mask (cell ID 0xFFFFFF) in the generated image. Defaults to True.
743
+
744
+ Returns:
745
+ ndarray: Array representing the generated image.
746
+ """
747
+ new_img = np.zeros_like(cell_id)
748
+ for cell in list_of_cells_to_plot:
749
+ new_img[cell_id == cell] = color
750
+ if keep_mask:
751
+ new_img[cell_id == 0xFFFFFF] = 0xFFFFFF
752
+ return new_img
753
+
754
+
755
+ @njit
756
+ def get_border_cells(img, bg_color=None):
757
+ """
758
+ Retrieves the border cells from an image.
759
+
760
+ Args:
761
+ img (ndarray): Array representing the image.
762
+ bg_color (int, optional): Background color of the image. Defaults to None.
763
+
764
+ Returns:
765
+ list: List of border cells.
766
+ """
767
+ border_cells = []
768
+ for j in range(img.shape[0]):
769
+ border_cells.append(img[j, 0])
770
+ border_cells.append(img[j, 1])
771
+ border_cells.append(img[j, img.shape[1]-1])
772
+ border_cells.append(img[j, img.shape[1]-2])
773
+
774
+ for i in range(img.shape[1]):
775
+ border_cells.append(img[0, i])
776
+ border_cells.append(img[1, i])
777
+ border_cells.append(img[img.shape[0]-1, i])
778
+ border_cells.append(img[img.shape[0]-2, i])
779
+
780
+ border_cells = list(set(border_cells))
781
+ if bg_color is not None:
782
+ if bg_color in border_cells:
783
+ border_cells.remove(bg_color)
784
+ return border_cells
785
+
786
+
787
+ def plot_dividing_cells_a_la_TA(img, dividing_pairs, plot_cell_outline=True,
788
+ exclude_cells_bigger_than_percent_of_image=20,
789
+ exclude_cells_with_size_difference_superior=3,
790
+ remove_divisions_involving_a_border_cell=True):
791
+ """
792
+ Generates an image highlighting cell divisions based on the provided dividing pairs.
793
+
794
+ Args:
795
+ img (ndarray): Array representing the image.
796
+ dividing_pairs (dict): Dictionary containing the dividing pairs of cells.
797
+ plot_cell_outline (bool, optional): Whether to plot the outline of cells. Defaults to True.
798
+ exclude_cells_bigger_than_percent_of_image (int, optional): Percentage of the image area above which cells are excluded. Defaults to 20.
799
+ exclude_cells_with_size_difference_superior (int, optional): Size difference ratio above which cells are excluded. Defaults to 3.
800
+ remove_divisions_involving_a_border_cell (bool, optional): Whether to remove divisions involving a border cell. Defaults to True.
801
+
802
+ Returns:
803
+ ndarray: Array representing the image with highlighted cell divisions.
804
+ """
805
+ if len(img.shape) == 3:
806
+ img = RGB_to_int24(img)
807
+
808
+ cell_divisions = np.zeros_like(img)
809
+ img_area = cell_divisions.shape[0] * cell_divisions.shape[1]
810
+
811
+ border_cells = None
812
+ if remove_divisions_involving_a_border_cell:
813
+ border_cells = get_border_cells(img)
814
+
815
+ div_counter = 0
816
+ for sister1, sister2 in dividing_pairs.items():
817
+
818
+ if remove_divisions_involving_a_border_cell:
819
+ if sister1 in border_cells or sister2 in border_cells:
820
+ continue
821
+
822
+ if exclude_cells_bigger_than_percent_of_image is not None and exclude_cells_with_size_difference_superior > 0:
823
+ sister_1_size = cell_divisions[img == sister1].size
824
+ sister_2_size = cell_divisions[img == sister2].size
825
+ if (sister_1_size + sister_2_size) / img_area >= exclude_cells_with_size_difference_superior / 100.:
826
+ continue
827
+ if exclude_cells_with_size_difference_superior is not None and exclude_cells_with_size_difference_superior != 0:
828
+ size_ratio = cell_divisions[img == sister1].size / cell_divisions[img == sister2].size
829
+
830
+ if size_ratio < 1:
831
+ size_ratio = 1. / size_ratio
832
+
833
+ if size_ratio > exclude_cells_with_size_difference_superior:
834
+ continue
835
+
836
+ cell_divisions[img == sister1] = div_counter + 1
837
+ cell_divisions[img == sister2] = div_counter + 1
838
+
839
+ div_counter += 1
840
+
841
+ if plot_cell_outline:
842
+ cell_divisions[img == 0xFFFFFF] = 0xFFFFFF
843
+
844
+ return cell_divisions
845
+
846
+ def optimize_score(cells_and_their_neighbors_cur, cells_and_their_neighbors_t_other, current_cells_n_score,
847
+ map_tracks_n_label_t_cur, threshold=0.5):
848
+ # if shift is validated I need change the mappings --> either swap cells or swap their values --> the pb is that this will change the relationship to the rps --> need be smart but ok
849
+ # convert map_tracks_n_label_t_cur to a dict then convert it back to array after all changes are applied
850
+
851
+ tmp_map_tracks_n_label_t_cur = {k: v for k, v in map_tracks_n_label_t_cur}
852
+
853
+ # print('tmp_map_tracks_n_label_t_cur', tmp_map_tracks_n_label_t_cur) # --> ok mais ensuite perd tt --> why???
854
+ # print(len(tmp_map_tracks_n_label_t_cur))
855
+
856
+ # sort current_cells_n_score values and keys from min to max until a threshold try to optimize score
857
+ # find if any other pair improves score !!! and if so do the swap and recompute the score
858
+ # probably need update all in the lists too --> TODO
859
+ # or do not do recursively --> check that later --> first try find and see if score improves
860
+ possible_swapping_pairs = {}
861
+ possible_assignment = {}
862
+
863
+ # nb maybe compute the score here --> no need to do it outside then --> simpler
864
+ scores_sorted_ascending = dict(sorted(current_cells_n_score.items(), key=operator.itemgetter(1)))
865
+ low_scores_to_check = [cell for cell in scores_sorted_ascending.keys() if
866
+ scores_sorted_ascending[cell] <= threshold]
867
+
868
+ # print('scores_sorted_descending', scores_sorted_ascending)
869
+ # print('scores_sorted_descending', [r_g_b_from_rgb(cell) for cell in scores_sorted_ascending.keys()])
870
+ # # if r_g_b_to_rgb(252, 78, 252) in scores_sorted_ascending.keys():
871
+ # # print('score ', scores_sorted_ascending[r_g_b_to_rgb(252, 78, 252)], r_g_b_to_rgb(252, 78, 252))
872
+ # # else:
873
+ # # print('score not in')
874
+ # print('low_scores_to_check', low_scores_to_check)
875
+ # print('in stuff to chekc', r_g_b_to_rgb(156, 248, 184) in low_scores_to_check,
876
+ # r_g_b_to_rgb(156, 248, 184)) # false --> this cell has a score of 1.0 --> how is it possible ???
877
+ # print('in stuff to chekc', r_g_b_to_rgb(66, 162, 164) in low_scores_to_check,
878
+ # r_g_b_to_rgb(66, 162, 164)) # true --> score 0.6 --> ok
879
+ # print('in stuff to chekc2', r_g_b_to_rgb(137, 134, 15) in low_scores_to_check,
880
+ # r_g_b_to_rgb(137, 134, 15)) # true --> score 0.6 --> ok
881
+
882
+ # try:
883
+ # print(r_g_b_to_rgb(156, 248, 184) in cells_and_their_neighbors_cur,
884
+ # r_g_b_to_rgb(156, 248, 184) in cells_and_their_neighbors_t_other)
885
+ # print('manually calculated score', pairwise_score(cells_and_their_neighbors_cur[r_g_b_to_rgb(156, 248, 184)],
886
+ # cells_and_their_neighbors_t_other[
887
+ # r_g_b_to_rgb(156, 248, 184)]),
888
+ # cells_and_their_neighbors_cur[r_g_b_to_rgb(156, 248, 184)],
889
+ # cells_and_their_neighbors_t_other[r_g_b_to_rgb(156, 248, 184)])
890
+ # print('manually calculated score2', pairwise_score(cells_and_their_neighbors_cur[r_g_b_to_rgb(66, 162, 164)],
891
+ # cells_and_their_neighbors_t_other[
892
+ # r_g_b_to_rgb(156, 248, 184)]),
893
+ # cells_and_their_neighbors_cur[r_g_b_to_rgb(66, 162, 164)],
894
+ # cells_and_their_neighbors_t_other[r_g_b_to_rgb(156, 248, 184)])
895
+ # print('manually calculated score3', pairwise_score(cells_and_their_neighbors_cur[r_g_b_to_rgb(156, 248, 184)],
896
+ # cells_and_their_neighbors_t_other[
897
+ # r_g_b_to_rgb(66, 162, 164)]),
898
+ # cells_and_their_neighbors_cur[r_g_b_to_rgb(156, 248, 184)],
899
+ # cells_and_their_neighbors_t_other[r_g_b_to_rgb(66, 162, 164)])
900
+ # except:
901
+ # print('missing cell')
902
+ # pass
903
+
904
+ # low_scores_to_check[980445, 4479535, 9829855, 10240303, 10369245, 10652374, 11560212, 16222777, 16404369] --> a l'air de marcher
905
+ # loop those over the entire list
906
+
907
+ # possible swap 16703757 980445
908
+ # possible swap 16703757 4479535
909
+ # possible swap 16703757 9829855
910
+ # possible swap None 10240303
911
+ # possible swap None 10369245
912
+ # possible swap 16703757 10652374
913
+ # possible swap None 11560212
914
+ # possible swap 16703757 16222777
915
+ # possible swap 16703757 16404369
916
+
917
+ # shall I store all possible swaps and then apply them in the end
918
+ # to improve the glocal score should improve
919
+
920
+ # it is in the stuff to check but never makes it to the end --> WHY
921
+
922
+ # possible assignment peut aussi detecter les paires en division--> très bonne idée
923
+
924
+ # TODO also check all possible swaps between pairs of cells with low score non 0 that would optimize global score
925
+ # pb is score if they share neighbs --> individual score not better because need take into account all
926
+ # maybe do brute force scoring for low cells once just to see
927
+
928
+ # brute force swap --> create all swapping pairs non zero and check them
929
+
930
+ for cell in low_scores_to_check:
931
+ current_score = current_cells_n_score[cell]
932
+ # print(current_score)
933
+ # TODO en fait c'est impossible car le score est tjrs inferieur à 1 sauf si l'utilisateur veut vraiment mettre 1 --> remove that or keep it to force analyze the whole image ??? --> I guess remove it
934
+ if current_score >= 1.0:
935
+ continue
936
+ final_cell_to_swap = None
937
+
938
+ # stuff below is a bit less good with best score... --> seems not a good idea but check that I have no bug some day
939
+ # best_score = 0.
940
+
941
+ if cell in cells_and_their_neighbors_t_other.keys():
942
+ neigbsb = cells_and_their_neighbors_t_other[cell]
943
+
944
+ # PB IS THAT I SHOULD ASSUME SCORE WITH ASSUMING BETTER SWAP
945
+ # look in neighborhood if there is a better match
946
+ # nb I could add its own neighbors by the way --> no need to only take those of the neighbor in prev --> need to check if it is a swap or an
947
+ for cell_to_swap_with, neigbs in cells_and_their_neighbors_cur.items():
948
+ if cell_to_swap_with == cell:
949
+ continue
950
+
951
+ # (len(list(set(neigbs) & set(neigbsb))) * 2) / (len(neigbsb) + len(neigbs))
952
+ score = pairwise_score(neigbs, neigbsb)
953
+
954
+ # if cell_to_swap_with == 4367012 and cell == 10287288:
955
+ # print('in da sgit', score, neigbs, neigbsb, current_score)
956
+
957
+ if score >= current_score:
958
+ current_score = score
959
+ final_cell_to_swap = cell_to_swap_with
960
+ # if score >= best_score:
961
+ # best_score = score
962
+ # final_cell_to_swap = cell_to_swap_with
963
+ if final_cell_to_swap is not None:
964
+ # if final_cell_to_swap is not None and best_score>0.:
965
+ # print('possible swap', cell, final_cell_to_swap, current_score, r_g_b_from_rgb(cell), r_g_b_from_rgb(final_cell_to_swap)) # indeed a perfect swap
966
+ possible_swapping_pairs[cell] = final_cell_to_swap
967
+ else:
968
+ # same code in fact -->
969
+ # la cellule n'est pas dans other --> verif si le swap est dans celui là sinon assigner le fate sinon creer une nouvelle id unique qui n'est ni dans l'un ni dans l'autre
970
+ # possible_assignment
971
+ # find any cell id that would share the max of the neighbors --> loop over all or loop over all that have low score and look for better
972
+
973
+ # probably only need loop over low scores --> most of the cells will not have that then!!!
974
+ # IN FCAT ONLY NEED BE DONE FOR NEW CELLS --> HUGE GAIN OF TIME!!!!
975
+ # for cellb, neigbsb in cells_and_their_neighbors_t_other.items():
976
+ # neigbsb = cells_and_their_neighbors_t_other[cell]
977
+ neigbsb = cells_and_their_neighbors_cur[cell]
978
+
979
+ for cell_to_swap_with, neigbs in cells_and_their_neighbors_t_other.items():
980
+ if cell_to_swap_with == cell:
981
+ continue
982
+ score = pairwise_score(neigbs,
983
+ neigbsb) # (len(list(set(neigbs) & set(neigbsb))) * 2) / (len(neigbsb) + len(neigbs))
984
+ if score > current_score:
985
+ current_score = score
986
+ final_cell_to_swap = cell_to_swap_with
987
+ # if score > best_score:
988
+ # best_score = score
989
+ # final_cell_to_swap = cell_to_swap_with
990
+ if final_cell_to_swap is not None:
991
+ # if final_cell_to_swap is not None and best_score > 0.:
992
+ # print('possible assignment', cell, final_cell_to_swap, current_score, r_g_b_from_rgb(cell), r_g_b_from_rgb(final_cell_to_swap), current_score) # indeed a perfect swap
993
+ possible_assignment[cell] = final_cell_to_swap
994
+ # pass
995
+
996
+ # check if any of the lost cells in current would give a better score than a cell in the current because if that is the case --> offer assignment
997
+ missing_cells_from_prev = set(cells_and_their_neighbors_t_other.keys()) - set(cells_and_their_neighbors_cur.keys())
998
+
999
+ # print('in stuff to chekc2b', r_g_b_to_rgb(137, 134, 15) in missing_cells_from_prev, r_g_b_to_rgb(137, 134, 15), r_g_b_to_rgb(44, 140, 93)) # true --> score 0.6 --> ok
1000
+ if True:
1001
+ for cell in missing_cells_from_prev:
1002
+ best_score = 0
1003
+ # comme c'est du brute force ça rallonge pas mal le processus, pr finalement très peu de cellules --> is that really worth it ???
1004
+ final_cell_to_swap = None
1005
+ neigbsb = cells_and_their_neighbors_t_other[cell]
1006
+ for cell_to_swap_with, neigbs in cells_and_their_neighbors_cur.items():
1007
+ current_score = current_cells_n_score[cell_to_swap_with]
1008
+ if current_score >= 1.:
1009
+ continue
1010
+
1011
+ score = pairwise_score(neigbs,
1012
+ neigbsb) # (len(list(set(neigbs) & set(neigbsb))) * 2) / (len(neigbsb) + len(neigbs))
1013
+
1014
+ if score >= current_score:
1015
+ # current_score = score
1016
+ if score >= best_score:
1017
+ best_score = score
1018
+ final_cell_to_swap = cell_to_swap_with
1019
+ if final_cell_to_swap is not None:
1020
+ # print('possible assignment2', cell, final_cell_to_swap, current_score, r_g_b_from_rgb(cell), r_g_b_from_rgb(final_cell_to_swap), current_score) # indeed a perfect swap
1021
+ possible_assignment[final_cell_to_swap] = cell
1022
+ # if any of these cells gives a better score than the current offer a swap
1023
+
1024
+ # this cell never enters here although there has to be an equal cell maybe
1025
+ # print('inside swaps and so on', r_g_b_to_rgb(156, 248, 184) in possible_assignment.keys(), r_g_b_to_rgb(156, 248, 184) in possible_assignment.values(), r_g_b_to_rgb(156, 248, 184) in possible_swapping_pairs.keys(), r_g_b_to_rgb(156, 248, 184) in possible_swapping_pairs.values())
1026
+
1027
+ # the two cells never enter in this !!!
1028
+ # print('inside swaps and so on', r_g_b_to_rgb(156, 248, 184) in possible_assignment.keys(),
1029
+ # r_g_b_to_rgb(156, 248, 184) in possible_assignment.values(),
1030
+ # r_g_b_to_rgb(156, 248, 184) in possible_swapping_pairs.keys(),
1031
+ # r_g_b_to_rgb(156, 248, 184) in possible_swapping_pairs.values())
1032
+ # print('inside swaps and so on', r_g_b_to_rgb(66, 162, 164) in possible_assignment.keys(),
1033
+ # r_g_b_to_rgb(66, 162, 164) in possible_assignment.values(),
1034
+ # r_g_b_to_rgb(66, 162, 164) in possible_swapping_pairs.keys(),
1035
+ # r_g_b_to_rgb(66, 162, 164) in possible_swapping_pairs.values())
1036
+
1037
+ # maybe store al the possible swaps and apply them and try
1038
+ # low scores could even contain new cells
1039
+ # score TODO finalize that
1040
+ # print('total score after optimization', sum(cells_present_in_t_cur_but_absent_in_t_minus_1_score.values()))
1041
+
1042
+ # get the dict and copy it
1043
+
1044
+ import copy
1045
+ cp = copy.deepcopy(cells_and_their_neighbors_cur)
1046
+ initial_score = sum(current_cells_n_score.values())
1047
+ # new_score= initial_score
1048
+
1049
+ print('initila score', initial_score)
1050
+
1051
+ final_validated_changes = {}
1052
+
1053
+ # I need treat the swapping and assignment differently!!!
1054
+
1055
+ # in fact if the cell is present in the image --> real swapping and can be added otherwise it's an assignment --> do things differently
1056
+ # need further filter
1057
+
1058
+ # FILTER AGAIN assignments
1059
+ # AN ASSIGNMENT SHOULD HAVE ONLY ONE CELL IN THE IMAGE
1060
+
1061
+ # filtered_assignments = {k : v for (k,v) in possible_assignment.items()}
1062
+ # keys to remove:
1063
+ keys_to_remove_in_assignment = []
1064
+ print('possible_assignment', possible_assignment)
1065
+ for k, v in possible_assignment.items():
1066
+ if v in cells_and_their_neighbors_cur.keys():
1067
+ # del possible_assignment[k]
1068
+ keys_to_remove_in_assignment.append(k)
1069
+
1070
+ for k in keys_to_remove_in_assignment:
1071
+ del possible_assignment[k]
1072
+
1073
+ print('filtered_assignments',
1074
+ possible_assignment) # --> good really kept the right one, but keep in mind that the others are actually missegmented cells in current --> those are very useful and I have positional info there --> maybe keep those
1075
+
1076
+ for cell, val in possible_assignment.items():
1077
+ # just change the fate of the key and replace it in itself and in neighboring cells!!!
1078
+ # much less operations than in the other --> TODO
1079
+ neighbs_cell = cells_and_their_neighbors_cur[cell]
1080
+ for neigb in neighbs_cell:
1081
+ neighbs_of_neighb = cells_and_their_neighbors_cur[neigb]
1082
+ neighbs_of_neighb = [id if id != cell else val for id in neighbs_of_neighb]
1083
+ cells_and_their_neighbors_cur[neigb] = neighbs_of_neighb
1084
+ # print('cell in neighbs_of_neighb', cell in neighbs_of_neighb) # FAlse --> ok indeed
1085
+ # print('val in neighbs_of_neighb',val in neighbs_of_neighb) # True --> all is ok in fact
1086
+
1087
+ # create a new cell then remove it
1088
+ cells_and_their_neighbors_cur[val] = cells_and_their_neighbors_cur[cell]
1089
+ del cells_and_their_neighbors_cur[cell]
1090
+ new_score = compute_neighbor_score(cells_and_their_neighbors_cur=cells_and_their_neighbors_cur,
1091
+ cells_and_their_neighbors_t_other=cells_and_their_neighbors_t_other)
1092
+ print('new_score, initial_score', new_score, initial_score)
1093
+
1094
+ if new_score <= initial_score:
1095
+ # do not change if score is lower or equal --> TODO
1096
+ # then restore change
1097
+ # cells_and_their_neighbors_cur[cell], cells_and_their_neighbors_cur[val] = cells_and_their_neighbors_cur[val], cells_and_their_neighbors_cur[cell]
1098
+ # reswap and restore
1099
+ # cells_and_their_neighbors_cur[cell]=bckup_neighbs_cell
1100
+ # cells_and_their_neighbors_cur[val]=bckup_neighbs_val
1101
+ cells_and_their_neighbors_cur = copy.deepcopy(cp)
1102
+ # else validate the list and continue
1103
+ # print('rejected assignment ', cell, val, r_g_b_from_rgb(cell), r_g_b_from_rgb(val), new_score, initial_score)
1104
+
1105
+
1106
+ else:
1107
+ # validate the change and update the score
1108
+ initial_score = new_score
1109
+ final_validated_changes[cell] = val
1110
+ cp = copy.deepcopy(cells_and_their_neighbors_cur)
1111
+
1112
+ # do I have an inversion ??? --> maybe yes ????
1113
+ # prevent multi assignments ??? or update the image in fact --> that is necessary
1114
+
1115
+ # print('accepted assignment', cell, val, r_g_b_from_rgb(cell), r_g_b_from_rgb(val), new_score, initial_score)
1116
+ # print(cell in cells_and_their_neighbors_cur.keys()) # FAlse --> ok indeed
1117
+ # print(val in cells_and_their_neighbors_cur.keys()) # True --> all is ok in fact
1118
+
1119
+ # update correspondance between cell and its mask
1120
+ print('before mapping0', cell, val, tmp_map_tracks_n_label_t_cur[cell])
1121
+ tmp_map_tracks_n_label_t_cur[val] = tmp_map_tracks_n_label_t_cur[cell]
1122
+ del tmp_map_tracks_n_label_t_cur[cell]
1123
+ print('after mapping0', cell, val, tmp_map_tracks_n_label_t_cur[val])
1124
+
1125
+ cp = copy.deepcopy(cells_and_their_neighbors_cur)
1126
+ # TODO by construction it does it both ways and I don't want that because it's a waste of time --> need fix that and change that --> if already validated prevent reswap
1127
+ # en fait c'est pas des swaps c'est des connexions de tracks
1128
+ for key, val in possible_swapping_pairs.items():
1129
+ # I need get the score after swap vs before for the cell and all of its neighbors recusrsively and only to that if all improves !!!
1130
+ for cell, neighbs in cells_and_their_neighbors_cur.items():
1131
+ if cell == key:
1132
+ # do the swap
1133
+ if val in cells_and_their_neighbors_cur.keys():
1134
+
1135
+ if val in final_validated_changes.keys():
1136
+ if final_validated_changes[val] == key:
1137
+ # prevent reswapping an already swapped stuff --> move on
1138
+ print('already swapped --> skipping', cell, val)
1139
+ continue
1140
+
1141
+ # in fact I need also store and restore all neighbs --> need do complex copies of the stuff
1142
+ # bckup_neighbs_cell = list(cells_and_their_neighbors_cur[cell])
1143
+ # should I do that before or after by the way --> before is better
1144
+ neighbs_cell = cells_and_their_neighbors_cur[cell]
1145
+ for neigb in neighbs_cell:
1146
+ neighbs_of_neighb = cells_and_their_neighbors_cur[neigb]
1147
+ if cell == 10287288:
1148
+ print('neighbval begin', neighbs_of_neighb)
1149
+ neighbs_of_neighb = [id if id != cell else val for id in neighbs_of_neighb]
1150
+ cells_and_their_neighbors_cur[neigb] = neighbs_of_neighb
1151
+ if cell == 10287288:
1152
+ print('neighbval end', neighbs_of_neighb)
1153
+
1154
+ # print("change", bckup_neighbs_cell, neighbs_cell, cell, val) # no change here !!! --> bug
1155
+
1156
+ # c pas ça --> pr ses neighbs --> change all values
1157
+ # neighbs_cell = [id if id!=cell else val for id in neighbs_cell]
1158
+
1159
+ # bckup_neighbs_val = list(cells_and_their_neighbors_cur[val])
1160
+ neighbs_val = cells_and_their_neighbors_cur[val]
1161
+ # if cell == 10287288:
1162
+ # print('neighbs_val before', neighbs_val)
1163
+ for neigb in neighbs_val:
1164
+ neighbs_of_neighb = cells_and_their_neighbors_cur[neigb]
1165
+ if cell == 10287288:
1166
+ print('neighbval begin', neighbs_of_neighb)
1167
+ neighbs_of_neighb = [id if id != val else cell for id in neighbs_of_neighb]
1168
+ cells_and_their_neighbors_cur[neigb] = neighbs_of_neighb
1169
+
1170
+ if cell == 10287288:
1171
+ print('neighbval end', neighbs_of_neighb)
1172
+
1173
+ # if cell == 10287288:
1174
+ # print('neighbs_val after', neighbs_val)
1175
+ # print("change2", bckup_neighbs_val, neighbs_val, cell, val)
1176
+
1177
+ # neighbs_val = [id if id != val else cell for id in neighbs_val]
1178
+ # need replace val by cell in one and vice versa
1179
+
1180
+ cells_and_their_neighbors_cur[cell], cells_and_their_neighbors_cur[val] = \
1181
+ cells_and_their_neighbors_cur[val], cells_and_their_neighbors_cur[cell]
1182
+
1183
+ # print(type(cells_and_their_neighbors_cur), type(cells_and_their_neighbors_t_other)) # le second est une liste mais ne devrait pas !!!! --> un bug qq part
1184
+
1185
+ # here I could gain a lot of time by just computing the delta score change for the changed values only !!! --> in fact very good idea and would save a lot of time
1186
+
1187
+ # if cell == 10287288:
1188
+ # try:
1189
+ # print('cells for scoring', cells_and_their_neighbors_cur[10287288],
1190
+ # cells_and_their_neighbors_t_other[10287288], cells_and_their_neighbors_cur[4367012],
1191
+ # cells_and_their_neighbors_t_other[4367012])
1192
+ # except:
1193
+ # pass
1194
+
1195
+ new_score = compute_neighbor_score(cells_and_their_neighbors_cur=cells_and_their_neighbors_cur,
1196
+ cells_and_their_neighbors_t_other=cells_and_their_neighbors_t_other)
1197
+ print('new_score, initial_score', new_score, initial_score)
1198
+
1199
+ if new_score <= initial_score:
1200
+ # do not change if score is lower or equal --> TODO
1201
+ # then restore change
1202
+ # cells_and_their_neighbors_cur[cell], cells_and_their_neighbors_cur[val] = cells_and_their_neighbors_cur[val], cells_and_their_neighbors_cur[cell]
1203
+ # reswap and restore
1204
+ # cells_and_their_neighbors_cur[cell]=bckup_neighbs_cell
1205
+ # cells_and_their_neighbors_cur[val]=bckup_neighbs_val
1206
+ cells_and_their_neighbors_cur = copy.deepcopy(cp)
1207
+ # else validate the list and continue
1208
+ # print('rejected changes ', cell, val, r_g_b_from_rgb(cell), r_g_b_from_rgb(val), new_score, initial_score)
1209
+
1210
+ else:
1211
+ # validate the change and update the score
1212
+ initial_score = new_score
1213
+ final_validated_changes[cell] = val
1214
+ cp = copy.deepcopy(cells_and_their_neighbors_cur)
1215
+ # print('accepted change', cell, val, r_g_b_from_rgb(cell), r_g_b_from_rgb(val), new_score, initial_score)
1216
+
1217
+ # apply changes to the dict and return it too
1218
+
1219
+ print('before mapping', cell, val, tmp_map_tracks_n_label_t_cur[cell], tmp_map_tracks_n_label_t_cur[val])
1220
+ tmp_map_tracks_n_label_t_cur[cell], tmp_map_tracks_n_label_t_cur[val] = \
1221
+ tmp_map_tracks_n_label_t_cur[val], tmp_map_tracks_n_label_t_cur[cell]
1222
+ print('after mapping', cell, val, tmp_map_tracks_n_label_t_cur[cell], tmp_map_tracks_n_label_t_cur[val])
1223
+
1224
+ # TODO also need update their neighbors
1225
+
1226
+ # if global_score is improved keep change otherwise reset it
1227
+ # just do paiwise score --> easiest and if better --> keep
1228
+
1229
+ print('final_validated_changes', final_validated_changes)
1230
+
1231
+
1232
+
1233
+ # then recompute the score and if better --> change --> need compute the score for all cells implicated in
1234
+
1235
+ # ne pas utiliser un dict mais plutot le truc splitte et ne pas causer de
1236
+ #
1237
+ # d['A'], d['B'] = d['B'], d['A'] --> this is how to swapp values
1238
+ # to swap I should compare the dict to itself --> in that case this is pure swap --> but still need score with respect to the prev image !!!
1239
+ # sinon c'est assignment --> mais peut dupliquer id --> need swap
1240
+ # see how to do ???
1241
+
1242
+ # in the end apply this maybe one by one
1243
+
1244
+ # convert dict back to an array
1245
+
1246
+ print('tmp_map_tracks_n_label_t_cur2', len(tmp_map_tracks_n_label_t_cur))
1247
+
1248
+ tmp_map_tracks_n_label_t_cur = np.array(list(tmp_map_tracks_n_label_t_cur.items()))
1249
+
1250
+ print('tmp_map_tracks_n_label_t_curshp', tmp_map_tracks_n_label_t_cur.shape)
1251
+
1252
+
1253
+ # nb could also return score to see if worth continuing
1254
+
1255
+ return cells_and_their_neighbors_cur, tmp_map_tracks_n_label_t_cur, initial_score # need reconvert it to an array
1256
+
1257
+
1258
+ # this is a local and thereby faster version of the swap stuff
1259
+ # local and makes sure always the best cell is checked --> maybe smarter...
1260
+ # vachement de swap mais des bonnes idees faudrait faire des tests pr comprendre où ça bugge
1261
+ def optimize_score_local(cells_and_their_neighbors_cur, cells_and_their_neighbors_t_other, current_cells_n_score,
1262
+ map_tracks_n_label_t_cur, threshold=0.5):
1263
+ # if shift is validated I need change the mappings --> either swap cells or swap their values --> the pb is that this will change the relationship to the rps --> need be smart but ok
1264
+ # convert map_tracks_n_label_t_cur to a dict then convert it back to array after all changes are applied
1265
+
1266
+ tmp_map_tracks_n_label_t_cur = {k: v for k, v in map_tracks_n_label_t_cur}
1267
+
1268
+ print('tmp_map_tracks_n_label_t_cur', tmp_map_tracks_n_label_t_cur) # --> ok
1269
+
1270
+ # sort current_cells_n_score values and keys from min to max until a threshold try to optimize score
1271
+ # find if any other pair improves score !!! and if so do the swap and recompute the score
1272
+ # probably need update all in the lists too --> TODO
1273
+ # or do not do recursively --> check that later --> first try find and see if score improves
1274
+ possible_swapping_pairs = {}
1275
+ possible_assignment = {}
1276
+
1277
+ # nb maybe compute the score here --> no need to do it outside then --> simpler
1278
+ scores_sorted_ascending = dict(sorted(current_cells_n_score.items(), key=operator.itemgetter(1)))
1279
+ low_scores_to_check = [cell for cell in scores_sorted_ascending.keys() if
1280
+ scores_sorted_ascending[cell] <= threshold]
1281
+
1282
+ print('scores_sorted_descending', scores_sorted_ascending)
1283
+ # print('scores_sorted_descending', [r_g_b_from_rgb(cell) for cell in scores_sorted_ascending.keys()])
1284
+ # if r_g_b_to_rgb(252, 78, 252) in scores_sorted_ascending.keys():
1285
+ # print('score ', scores_sorted_ascending[r_g_b_to_rgb(252, 78, 252)], r_g_b_to_rgb(252, 78, 252))
1286
+ # else:
1287
+ # print('score not in')
1288
+ print('low_scores_to_check', low_scores_to_check)
1289
+ # print('in stuff to chekc', r_g_b_to_rgb(156, 248, 184) in low_scores_to_check, r_g_b_to_rgb(156, 248, 184)) # false --> this cell has a score of 1.0 --> how is it possible ???
1290
+ # print('in stuff to chekc', r_g_b_to_rgb(66, 162, 164) in low_scores_to_check, r_g_b_to_rgb(66, 162, 164)) # true --> score 0.6 --> ok
1291
+ # print('in stuff to chekc2', r_g_b_to_rgb(137, 134, 15) in low_scores_to_check, r_g_b_to_rgb(137, 134, 15)) # true --> score 0.6 --> ok
1292
+
1293
+ # try:
1294
+ # # print(r_g_b_to_rgb(156, 248, 184) in cells_and_their_neighbors_cur, r_g_b_to_rgb(156, 248, 184) in cells_and_their_neighbors_t_other)
1295
+ # print('manually calculated score', pairwise_score(cells_and_their_neighbors_cur[r_g_b_to_rgb(156, 248, 184)], cells_and_their_neighbors_t_other[r_g_b_to_rgb(156, 248, 184)]),
1296
+ # cells_and_their_neighbors_cur[r_g_b_to_rgb(156, 248, 184)],
1297
+ # cells_and_their_neighbors_t_other[r_g_b_to_rgb(156, 248, 184)])
1298
+ # print('manually calculated score2', pairwise_score(cells_and_their_neighbors_cur[r_g_b_to_rgb(66, 162, 164)],
1299
+ # cells_and_their_neighbors_t_other[
1300
+ # r_g_b_to_rgb(156, 248, 184)]),
1301
+ # cells_and_their_neighbors_cur[r_g_b_to_rgb(66, 162, 164)],
1302
+ # cells_and_their_neighbors_t_other[r_g_b_to_rgb(156, 248, 184)])
1303
+ # print('manually calculated score3', pairwise_score(cells_and_their_neighbors_cur[r_g_b_to_rgb(156, 248, 184)],
1304
+ # cells_and_their_neighbors_t_other[
1305
+ # r_g_b_to_rgb(66, 162, 164)]),
1306
+ # cells_and_their_neighbors_cur[r_g_b_to_rgb(156, 248, 184)],
1307
+ # cells_and_their_neighbors_t_other[r_g_b_to_rgb(66, 162, 164)])
1308
+ # except:
1309
+ # print('missing cell')
1310
+ # pass
1311
+
1312
+ # low_scores_to_check[980445, 4479535, 9829855, 10240303, 10369245, 10652374, 11560212, 16222777, 16404369] --> a l'air de marcher
1313
+ # loop those over the entire list
1314
+
1315
+ # possible swap 16703757 980445
1316
+ # possible swap 16703757 4479535
1317
+ # possible swap 16703757 9829855
1318
+ # possible swap None 10240303
1319
+ # possible swap None 10369245
1320
+ # possible swap 16703757 10652374
1321
+ # possible swap None 11560212
1322
+ # possible swap 16703757 16222777
1323
+ # possible swap 16703757 16404369
1324
+
1325
+ # shall I store all possible swaps and then apply them in the end
1326
+ # to improve the glocal score should improve
1327
+
1328
+ # it is in the stuff to check but never makes it to the end --> WHY
1329
+
1330
+ # possible assignment peut aussi detecter les paires en division--> très bonne idée
1331
+
1332
+ # TODO also check all possible swaps between pairs of cells with low score non 0 that would optimize global score
1333
+ # pb is score if they share neighbs --> individual score not better because need take into account all
1334
+ # maybe do brute force scoring for low cells once just to see
1335
+
1336
+ # brute force swap --> create all swapping pairs non zero and check them
1337
+
1338
+ for cell in low_scores_to_check:
1339
+ current_score = current_cells_n_score[cell]
1340
+ print(current_score)
1341
+ # TODO en fait c'est impossible car le score est tjrs inferieur à 1 sauf si l'utilisateur veut vraiment mettre 1 --> remove that or keep it to force analyze the whole image ??? --> I guess remove it
1342
+ if current_score >= 1.0:
1343
+ continue
1344
+ final_cell_to_swap = None
1345
+ # ssqdqsdqdqs
1346
+ best_score = 0
1347
+ # shall I really try all possible swap pairs ??? rather than try best or should I at least try one --> maybe yes --> the one with the best score
1348
+ possible_swaps, possible_assignments = find_neighbors_to_check(cell, cells_and_their_neighbors_cur, cells_and_their_neighbors_t_other)
1349
+ # should I pass all those cells directly without recomputing the score --> probably yes in fact
1350
+ if cell in cells_and_their_neighbors_t_other.keys():
1351
+ # could even add its own neighbs because if a swap helps then really do it!!!
1352
+ neigbsb = cells_and_their_neighbors_t_other[cell]
1353
+
1354
+ # PB IS THAT I SHOULD ASSUME SCORE WITH ASSUMING BETTER SWAP
1355
+ # look in neighborhood if there is a better match
1356
+ # nb I could add its own neighbors by the way --> no need to only take those of the neighbor in prev --> need to check if it is a swap or an
1357
+ # brute force too --> does check all the cells in the image
1358
+ # for cell_to_swap_with, neigbs in cells_and_their_neighbors_cur.items():
1359
+ for cell_to_swap_with in possible_swaps:
1360
+ if cell_to_swap_with == cell:
1361
+ continue
1362
+ neigbs = cells_and_their_neighbors_cur[cell_to_swap_with]
1363
+
1364
+ # (len(list(set(neigbs) & set(neigbsb))) * 2) / (len(neigbsb) + len(neigbs))
1365
+ score = pairwise_score(neigbs, neigbsb)
1366
+
1367
+ if cell_to_swap_with == 4367012 and cell == 10287288:
1368
+ print('in da sgit', score, neigbs, neigbsb, current_score)
1369
+
1370
+ if score >= best_score :
1371
+ best_score = score
1372
+ final_cell_to_swap = cell_to_swap_with
1373
+ if final_cell_to_swap is not None and best_score>0.:
1374
+ # print('possible swap', cell, final_cell_to_swap, current_score, r_g_b_from_rgb(cell),
1375
+ # r_g_b_from_rgb(final_cell_to_swap)) # indeed a perfect swap
1376
+ possible_swapping_pairs[cell] = final_cell_to_swap
1377
+ else:
1378
+ # same code in fact -->
1379
+ # la cellule n'est pas dans other --> verif si le swap est dans celui là sinon assigner le fate sinon creer une nouvelle id unique qui n'est ni dans l'un ni dans l'autre
1380
+ # possible_assignment
1381
+ # find any cell id that would share the max of the neighbors --> loop over all or loop over all that have low score and look for better
1382
+
1383
+ # probably only need loop over low scores --> most of the cells will not have that then!!!
1384
+ # IN FCAT ONLY NEED BE DONE FOR NEW CELLS --> HUGE GAIN OF TIME!!!!
1385
+ # for cellb, neigbsb in cells_and_their_neighbors_t_other.items():
1386
+ # neigbsb = cells_and_their_neighbors_t_other[cell]
1387
+ neigbsb = cells_and_their_neighbors_cur[cell]
1388
+
1389
+ # for cell_to_swap_with, neigbs in cells_and_their_neighbors_t_other.items():
1390
+ for cell_to_swap_with in possible_assignments:
1391
+ if cell_to_swap_with == cell:
1392
+ continue
1393
+ neigbs = cells_and_their_neighbors_t_other[cell_to_swap_with]
1394
+ score = pairwise_score(neigbs,
1395
+ neigbsb) # (len(list(set(neigbs) & set(neigbsb))) * 2) / (len(neigbsb) + len(neigbs))
1396
+ if score > best_score:
1397
+ best_score = score
1398
+ final_cell_to_swap = cell_to_swap_with
1399
+ if final_cell_to_swap is not None and best_score>0:
1400
+ # print('possible assignment', cell, final_cell_to_swap, current_score, r_g_b_from_rgb(cell),
1401
+ # r_g_b_from_rgb(final_cell_to_swap), current_score) # indeed a perfect swap
1402
+ possible_assignment[cell] = final_cell_to_swap
1403
+ # pass
1404
+
1405
+ # check if any of the lost cells in current would give a better score than a cell in the current because if that is the case --> offer assignment
1406
+ missing_cells_from_prev = set(cells_and_their_neighbors_t_other.keys()) - set(cells_and_their_neighbors_cur.keys())
1407
+
1408
+ print('in stuff to chekc2b', r_g_b_to_rgb(137, 134, 15) in missing_cells_from_prev,
1409
+ r_g_b_to_rgb(137, 134, 15), r_g_b_to_rgb(44, 140, 93)) # true --> score 0.6 --> ok
1410
+ if True:
1411
+ for cell in missing_cells_from_prev:
1412
+ best_score = 0
1413
+ # comme c'est du brute force ça rallonge pas mal le processus, pr finalement très peu de cellules --> is that really worth it ???
1414
+ final_cell_to_swap = None
1415
+ neigbsb = cells_and_their_neighbors_t_other[cell]
1416
+ for cell_to_swap_with, neigbs in cells_and_their_neighbors_cur.items():
1417
+ current_score = current_cells_n_score[cell_to_swap_with]
1418
+ if current_score >= 1.:
1419
+ continue
1420
+
1421
+ score = pairwise_score(neigbs,
1422
+ neigbsb) # (len(list(set(neigbs) & set(neigbsb))) * 2) / (len(neigbsb) + len(neigbs))
1423
+
1424
+ if score >= current_score:
1425
+ # current_score = score
1426
+ if score >= best_score:
1427
+ best_score = score
1428
+ final_cell_to_swap = cell_to_swap_with
1429
+ if final_cell_to_swap is not None:
1430
+ # print('possible assignment2', cell, final_cell_to_swap, current_score, r_g_b_from_rgb(cell),
1431
+ # r_g_b_from_rgb(final_cell_to_swap), current_score) # indeed a perfect swap
1432
+ possible_assignment[final_cell_to_swap] = cell
1433
+ # if any of these cells gives a better score than the current offer a swap
1434
+
1435
+ # this cell never enters here although there has to be an equal cell maybe
1436
+ # print('inside swaps and so on', r_g_b_to_rgb(156, 248, 184) in possible_assignment.keys(), r_g_b_to_rgb(156, 248, 184) in possible_assignment.values(), r_g_b_to_rgb(156, 248, 184) in possible_swapping_pairs.keys(), r_g_b_to_rgb(156, 248, 184) in possible_swapping_pairs.values())
1437
+
1438
+ # the two cells never enter in this !!!
1439
+ print('inside swaps and so on', r_g_b_to_rgb(156, 248, 184) in possible_assignment.keys(),
1440
+ r_g_b_to_rgb(156, 248, 184) in possible_assignment.values(),
1441
+ r_g_b_to_rgb(156, 248, 184) in possible_swapping_pairs.keys(),
1442
+ r_g_b_to_rgb(156, 248, 184) in possible_swapping_pairs.values())
1443
+ print('inside swaps and so on', r_g_b_to_rgb(66, 162, 164) in possible_assignment.keys(),
1444
+ r_g_b_to_rgb(66, 162, 164) in possible_assignment.values(),
1445
+ r_g_b_to_rgb(66, 162, 164) in possible_swapping_pairs.keys(),
1446
+ r_g_b_to_rgb(66, 162, 164) in possible_swapping_pairs.values())
1447
+
1448
+ # maybe store al the possible swaps and apply them and try
1449
+ # low scores could even contain new cells
1450
+ # score TODO finalize that
1451
+ # print('total score after optimization', sum(cells_present_in_t_cur_but_absent_in_t_minus_1_score.values()))
1452
+
1453
+ # get the dict and copy it
1454
+
1455
+ import copy
1456
+ cp = copy.deepcopy(cells_and_their_neighbors_cur)
1457
+ initial_score = sum(current_cells_n_score.values())
1458
+ # new_score= initial_score
1459
+
1460
+ print('initila score', initial_score)
1461
+
1462
+ final_validated_changes = {}
1463
+
1464
+ # I need treat the swapping and assignment differently!!!
1465
+
1466
+ # in fact if the cell is present in the image --> real swapping and can be added otherwise it's an assignment --> do things differently
1467
+ # need further filter
1468
+
1469
+ # FILTER AGAIN assignments
1470
+ # AN ASSIGNMENT SHOULD HAVE ONLY ONE CELL IN THE IMAGE
1471
+
1472
+ # filtered_assignments = {k : v for (k,v) in possible_assignment.items()}
1473
+ # keys to remove:
1474
+ keys_to_remove_in_assignment = []
1475
+ print('possible_assignment', possible_assignment)
1476
+ for k, v in possible_assignment.items():
1477
+ if v in cells_and_their_neighbors_cur.keys():
1478
+ # del possible_assignment[k]
1479
+ keys_to_remove_in_assignment.append(k)
1480
+
1481
+ for k in keys_to_remove_in_assignment:
1482
+ del possible_assignment[k]
1483
+
1484
+ print('filtered_assignments',
1485
+ possible_assignment) # --> good really kept the right one, but keep in mind that the others are actually missegmented cells in current --> those are very useful and I have positional info there --> maybe keep those
1486
+
1487
+ for cell, val in possible_assignment.items():
1488
+ # just change the fate of the key and replace it in itself and in neighboring cells!!!
1489
+ # much less operations than in the other --> TODO
1490
+ neighbs_cell = cells_and_their_neighbors_cur[cell]
1491
+ for neigb in neighbs_cell:
1492
+ neighbs_of_neighb = cells_and_their_neighbors_cur[neigb]
1493
+ neighbs_of_neighb = [id if id != cell else val for id in neighbs_of_neighb]
1494
+ cells_and_their_neighbors_cur[neigb] = neighbs_of_neighb
1495
+ # print('cell in neighbs_of_neighb', cell in neighbs_of_neighb) # FAlse --> ok indeed
1496
+ # print('val in neighbs_of_neighb',val in neighbs_of_neighb) # True --> all is ok in fact
1497
+
1498
+ # create a new cell then remove it
1499
+ cells_and_their_neighbors_cur[val] = cells_and_their_neighbors_cur[cell]
1500
+ del cells_and_their_neighbors_cur[cell]
1501
+ new_score = compute_neighbor_score(cells_and_their_neighbors_cur=cells_and_their_neighbors_cur,
1502
+ cells_and_their_neighbors_t_other=cells_and_their_neighbors_t_other)
1503
+ print('new_score, initial_score', new_score, initial_score)
1504
+
1505
+ if new_score < initial_score:
1506
+ # do not change if score is lower or equal --> TODO
1507
+ # then restore change
1508
+ # cells_and_their_neighbors_cur[cell], cells_and_their_neighbors_cur[val] = cells_and_their_neighbors_cur[val], cells_and_their_neighbors_cur[cell]
1509
+ # reswap and restore
1510
+ # cells_and_their_neighbors_cur[cell]=bckup_neighbs_cell
1511
+ # cells_and_their_neighbors_cur[val]=bckup_neighbs_val
1512
+ cells_and_their_neighbors_cur = copy.deepcopy(cp)
1513
+ # else validate the list and continue
1514
+ # print('rejected assignment ', cell, val, r_g_b_from_rgb(cell), r_g_b_from_rgb(val), new_score,
1515
+ # initial_score)
1516
+
1517
+
1518
+ else:
1519
+ # validate the change and update the score
1520
+ initial_score = new_score
1521
+ final_validated_changes[cell] = val
1522
+ cp = copy.deepcopy(cells_and_their_neighbors_cur)
1523
+
1524
+ # do I have an inversion ??? --> maybe yes ????
1525
+ # prevent multi assignments ??? or update the image in fact --> that is necessary
1526
+
1527
+ # print('accepted assignment', cell, val, r_g_b_from_rgb(cell), r_g_b_from_rgb(val), new_score, initial_score)
1528
+ # print(cell in cells_and_their_neighbors_cur.keys()) # FAlse --> ok indeed
1529
+ # print(val in cells_and_their_neighbors_cur.keys()) # True --> all is ok in fact
1530
+
1531
+ # update correspondance between cell and its mask
1532
+ print('before mapping0', cell, val, tmp_map_tracks_n_label_t_cur[cell])
1533
+ tmp_map_tracks_n_label_t_cur[val] = tmp_map_tracks_n_label_t_cur[cell]
1534
+ del tmp_map_tracks_n_label_t_cur[cell]
1535
+ print('after mapping0', cell, val, tmp_map_tracks_n_label_t_cur[val])
1536
+
1537
+ cp = copy.deepcopy(cells_and_their_neighbors_cur)
1538
+ # TODO by construction it does it both ways and I don't want that because it's a waste of time --> need fix that and change that --> if already validated prevent reswap
1539
+ # en fait c'est pas des swaps c'est des connexions de tracks
1540
+ for key, val in possible_swapping_pairs.items():
1541
+ # I need get the score after swap vs before for the cell and all of its neighbors recusrsively and only to that if all improves !!!
1542
+ for cell, neighbs in cells_and_their_neighbors_cur.items():
1543
+ if cell == key:
1544
+ # do the swap
1545
+ if val in cells_and_their_neighbors_cur.keys():
1546
+
1547
+ if val in final_validated_changes.keys():
1548
+ if final_validated_changes[val] == key:
1549
+ # prevent reswapping an already swapped stuff --> move on
1550
+ print('already swapped --> skipping', cell, val)
1551
+ continue
1552
+
1553
+ # in fact I need also store and restore all neighbs --> need do complex copies of the stuff
1554
+ # bckup_neighbs_cell = list(cells_and_their_neighbors_cur[cell])
1555
+ # should I do that before or after by the way --> before is better
1556
+ neighbs_cell = cells_and_their_neighbors_cur[cell]
1557
+ for neigb in neighbs_cell:
1558
+ neighbs_of_neighb = cells_and_their_neighbors_cur[neigb]
1559
+ if cell == 10287288:
1560
+ print('neighbval begin', neighbs_of_neighb)
1561
+ neighbs_of_neighb = [id if id != cell else val for id in neighbs_of_neighb]
1562
+ cells_and_their_neighbors_cur[neigb] = neighbs_of_neighb
1563
+ if cell == 10287288:
1564
+ print('neighbval end', neighbs_of_neighb)
1565
+
1566
+ # print("change", bckup_neighbs_cell, neighbs_cell, cell, val) # no change here !!! --> bug
1567
+
1568
+ # c pas ça --> pr ses neighbs --> change all values
1569
+ # neighbs_cell = [id if id!=cell else val for id in neighbs_cell]
1570
+
1571
+ # bckup_neighbs_val = list(cells_and_their_neighbors_cur[val])
1572
+ neighbs_val = cells_and_their_neighbors_cur[val]
1573
+ # if cell == 10287288:
1574
+ # print('neighbs_val before', neighbs_val)
1575
+ for neigb in neighbs_val:
1576
+ neighbs_of_neighb = cells_and_their_neighbors_cur[neigb]
1577
+ if cell == 10287288:
1578
+ print('neighbval begin', neighbs_of_neighb)
1579
+ neighbs_of_neighb = [id if id != val else cell for id in neighbs_of_neighb]
1580
+ cells_and_their_neighbors_cur[neigb] = neighbs_of_neighb
1581
+
1582
+ if cell == 10287288:
1583
+ print('neighbval end', neighbs_of_neighb)
1584
+
1585
+ # if cell == 10287288:
1586
+ # print('neighbs_val after', neighbs_val)
1587
+ # print("change2", bckup_neighbs_val, neighbs_val, cell, val)
1588
+
1589
+ # neighbs_val = [id if id != val else cell for id in neighbs_val]
1590
+ # need replace val by cell in one and vice versa
1591
+
1592
+ cells_and_their_neighbors_cur[cell], cells_and_their_neighbors_cur[val] = \
1593
+ cells_and_their_neighbors_cur[val], cells_and_their_neighbors_cur[cell]
1594
+
1595
+ # print(type(cells_and_their_neighbors_cur), type(cells_and_their_neighbors_t_other)) # le second est une liste mais ne devrait pas !!!! --> un bug qq part
1596
+
1597
+ # here I could gain a lot of time by just computing the delta score change for the changed values only !!! --> in fact very good idea and would save a lot of time
1598
+
1599
+ if cell == 10287288:
1600
+ try:
1601
+ print('cells for scoring', cells_and_their_neighbors_cur[10287288],
1602
+ cells_and_their_neighbors_t_other[10287288], cells_and_their_neighbors_cur[4367012],
1603
+ cells_and_their_neighbors_t_other[4367012])
1604
+ except:
1605
+ # no big deal debug
1606
+ pass
1607
+
1608
+ new_score = compute_neighbor_score(cells_and_their_neighbors_cur=cells_and_their_neighbors_cur,
1609
+ cells_and_their_neighbors_t_other=cells_and_their_neighbors_t_other)
1610
+ print('new_score, initial_score', new_score, initial_score)
1611
+
1612
+ if new_score < initial_score:
1613
+ # do not change if score is lower or equal --> TODO
1614
+ # then restore change
1615
+ # cells_and_their_neighbors_cur[cell], cells_and_their_neighbors_cur[val] = cells_and_their_neighbors_cur[val], cells_and_their_neighbors_cur[cell]
1616
+ # reswap and restore
1617
+ # cells_and_their_neighbors_cur[cell]=bckup_neighbs_cell
1618
+ # cells_and_their_neighbors_cur[val]=bckup_neighbs_val
1619
+ cells_and_their_neighbors_cur = copy.deepcopy(cp)
1620
+ # else validate the list and continue
1621
+ # print('rejected changes ', cell, val, r_g_b_from_rgb(cell), r_g_b_from_rgb(val), new_score,
1622
+ # initial_score)
1623
+
1624
+ else:
1625
+ # validate the change and update the score
1626
+ initial_score = new_score
1627
+ final_validated_changes[cell] = val
1628
+ cp = copy.deepcopy(cells_and_their_neighbors_cur)
1629
+ # print('accepted change', cell, val, r_g_b_from_rgb(cell), r_g_b_from_rgb(val), new_score,
1630
+ # initial_score)
1631
+
1632
+ # apply changes to the dict and return it too
1633
+
1634
+ print('before mapping', cell, val, tmp_map_tracks_n_label_t_cur[cell],
1635
+ tmp_map_tracks_n_label_t_cur[val])
1636
+ tmp_map_tracks_n_label_t_cur[cell], tmp_map_tracks_n_label_t_cur[val] = \
1637
+ tmp_map_tracks_n_label_t_cur[val], tmp_map_tracks_n_label_t_cur[cell]
1638
+ print('after mapping', cell, val, tmp_map_tracks_n_label_t_cur[cell],
1639
+ tmp_map_tracks_n_label_t_cur[val])
1640
+
1641
+ # TODO also need update their neighbors
1642
+
1643
+ # if global_score is improved keep change otherwise reset it
1644
+ # just do paiwise score --> easiest and if better --> keep
1645
+
1646
+ print('final_validated_changes', final_validated_changes)
1647
+ # then recompute the score and if better --> change --> need compute the score for all cells implicated in
1648
+
1649
+ # ne pas utiliser un dict mais plutot le truc splitte et ne pas causer de
1650
+ #
1651
+ # d['A'], d['B'] = d['B'], d['A'] --> this is how to swapp values
1652
+ # to swap I should compare the dict to itself --> in that case this is pure swap --> but still need score with respect to the prev image !!!
1653
+ # sinon c'est assignment --> mais peut dupliquer id --> need swap
1654
+ # see how to do ???
1655
+
1656
+ # in the end apply this maybe one by one
1657
+
1658
+ # convert dict back to an array
1659
+ tmp_map_tracks_n_label_t_cur = np.array(list(tmp_map_tracks_n_label_t_cur.items()))
1660
+
1661
+ # nb could also return score to see if worth continuing
1662
+
1663
+ return cells_and_their_neighbors_cur, tmp_map_tracks_n_label_t_cur, initial_score # need reconvert it to an array
1664
+
1665
+
1666
+ def track_cells(files):
1667
+ for iii in range(len(files)):
1668
+ # file_t0 = files[iii-1]
1669
+ # file_t1 = files[iii]
1670
+ #
1671
+ # print(file_t0, file_t1)
1672
+
1673
+ # TODO instead of getting 3 files --> just make it able to get n files with specific rules --> TODO
1674
+ files_to_read = get_n_files_from_list(files, iii, -1, 1)
1675
+ # print(files_to_read)
1676
+
1677
+ # TODO handle first ad last
1678
+
1679
+ if files_to_read[0] is None or files_to_read[len(files_to_read) - 1] is None:
1680
+ # first or last image missing --> skipping for now but generate code at some point
1681
+ print('missing files', files_to_read)
1682
+
1683
+ # in fact here I could make use of the data of two consecutive images
1684
+ # or should I try directly with 3 images ????
1685
+
1686
+ # think about it
1687
+ continue
1688
+
1689
+ # for file_to_read in files_to_read:
1690
+ extension = '.tif' # '.png' # '.tif' # '.png' # '.tif'
1691
+ TA_path_minus_1, track_t_minus_1 = smart_name_parser(files_to_read[0],
1692
+ ordered_output=['TA', 'tracked_cells_resized' + extension])
1693
+ TA_path_cur, track_t_cur = smart_name_parser(files_to_read[1],
1694
+ ordered_output=['TA', 'tracked_cells_resized' + extension])
1695
+ TA_path_plus_1, track_t_plus_1 = smart_name_parser(files_to_read[2],
1696
+ ordered_output=['TA', 'tracked_cells_resized' + extension])
1697
+
1698
+ # print(tracked_cells_resized)
1699
+ track_t_minus_1 = RGB_to_int24(Img(track_t_minus_1))
1700
+ track_t_cur = RGB_to_int24(Img(track_t_cur))
1701
+ track_t_plus_1 = RGB_to_int24(Img(track_t_plus_1))
1702
+
1703
+ # find_vertices(img)
1704
+
1705
+ # could compare this to the other
1706
+ # vertices_t_minus_1 = find_vertices(track_t_minus_1, return_vertices=True, return_bonds=False)
1707
+ # vertices_t_cur = find_vertices(track_t_cur, return_vertices=True, return_bonds=False)
1708
+ # vertices_t_plus_1 = find_vertices(track_t_plus_1, return_vertices=True, return_bonds=False)
1709
+ vertices_t_minus_1 = np.stack(np.where(track_t_minus_1 == 0xFFFFFF), axis=1) #find_vertices(track_t_minus_1, return_vertices=True, return_bonds=False)
1710
+ vertices_t_cur = np.stack(np.where(track_t_cur == 0xFFFFFF), axis=1) # find_vertices(track_t_cur, return_vertices=True, return_bonds=False)
1711
+ vertices_t_plus_1 = np.stack(np.where(track_t_plus_1 == 0xFFFFFF), axis=1) # find_vertices(track_t_plus_1, return_vertices=True, return_bonds=False)
1712
+ # plt.imshow(vertices)
1713
+ # plt.show()
1714
+
1715
+ # print(get_vx_neighbors(vertices, RGB24img=img)) # is that slow??? --
1716
+
1717
+ # 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
1718
+
1719
+ # ce truc est slow --> can I speed up using vertices --> most likely yes
1720
+ # 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
1721
+ # 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
1722
+ # aussi voir comment associer les vertices à une seule cellule --> car très utile
1723
+ # print() # a bit faster indeed but not outstanding
1724
+
1725
+ # 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
1726
+ cells_and_their_neighbors_minus_1 = np.unique(
1727
+ np.asarray(associate_cell_to_its_neighbors2(vertices_t_minus_1, track_t_minus_1)), axis=0)
1728
+ cells_and_their_neighbors_cur = np.unique(
1729
+ np.asarray(associate_cell_to_its_neighbors2(vertices_t_cur, track_t_cur)), axis=0)
1730
+ cells_and_their_neighbors_plus_1 = np.unique(
1731
+ np.asarray(associate_cell_to_its_neighbors2(vertices_t_plus_1, track_t_plus_1)), axis=0)
1732
+
1733
+ cells_and_their_neighbors_minus_1 = associate_cells_to_neighbors_ID_in_dict(cells_and_their_neighbors_minus_1)
1734
+ cells_and_their_neighbors_cur = associate_cells_to_neighbors_ID_in_dict(cells_and_their_neighbors_cur)
1735
+ cells_and_their_neighbors_plus_1 = associate_cells_to_neighbors_ID_in_dict(cells_and_their_neighbors_plus_1)
1736
+
1737
+ print('cells_and_their_neighbors_minus_1', cells_and_their_neighbors_minus_1)
1738
+ print('cells_and_their_neighbors_cur', cells_and_their_neighbors_cur)
1739
+ print('cells_and_their_neighbors_plus_1', cells_and_their_neighbors_plus_1)
1740
+
1741
+ # for all the common cells --> compute a score
1742
+ # nb of matching neighbs / total nb of neighbs in both
1743
+
1744
+ # create and color
1745
+
1746
+ cells_present_in_t_cur_but_absent_in_t_plus_1 = []
1747
+ cells_present_in_t_cur_but_absent_in_t_plus_1_score = {}
1748
+ matching_neighorhood_score_t_cur_with_t_plus_1 = np.zeros_like(track_t_cur, dtype=float)
1749
+
1750
+ compute_neighbor_score(cells_and_their_neighbors_cur, cells_and_their_neighbors_plus_1,
1751
+ cells_present_in_t_cur_but_absent_in_t_plus_1,
1752
+ cells_present_in_t_cur_but_absent_in_t_plus_1_score,
1753
+ matching_neighorhood_score_t_cur_with_t_plus_1, track_t_cur)
1754
+
1755
+ # for cell, neigbs in cells_and_their_neighbors_cur.items():
1756
+ # if cell in cells_and_their_neighbors_plus_1:
1757
+ # # compute score and color cell
1758
+ # neigbsb = cells_and_their_neighbors_plus_1[cell]
1759
+ # score = (len(list(set(neigbs) & set(neigbsb))) * 2) / (len(neigbsb) + len(neigbs))
1760
+ # cells_present_in_t_cur_but_absent_in_t_plus_1_score[cell]=score
1761
+ # matching_neighorhood_score_t_cur_with_t_plus_1[track_t_cur == cell] = score
1762
+ # else:
1763
+ # cells_present_in_t_cur_but_absent_in_t_plus_1.append(cell)
1764
+ # cells_present_in_t_cur_but_absent_in_t_plus_1_score[cell] = 0
1765
+
1766
+ cells_present_in_t_cur_but_absent_in_t_minus_1 = []
1767
+ cells_present_in_t_cur_but_absent_in_t_minus_1_score = {}
1768
+ matching_neighorhood_score_t_cur_with_t_minus_1 = np.zeros_like(track_t_cur, dtype=float)
1769
+
1770
+ compute_neighbor_score(cells_and_their_neighbors_cur, cells_and_their_neighbors_minus_1,
1771
+ cells_present_in_t_cur_but_absent_in_t_minus_1,
1772
+ cells_present_in_t_cur_but_absent_in_t_minus_1_score,
1773
+ matching_neighorhood_score_t_cur_with_t_minus_1, track_t_cur)
1774
+ # for cell, neigbs in cells_and_their_neighbors_cur.items():
1775
+ # if cell in cells_and_their_neighbors_minus_1:
1776
+ # # compute score and color cell
1777
+ # neigbsb=cells_and_their_neighbors_minus_1[cell]
1778
+ # score = (len(list(set(neigbs) & set(neigbsb)))*2)/(len(neigbsb)+len(neigbs))
1779
+ # cells_present_in_t_cur_but_absent_in_t_minus_1_score[cell]=score
1780
+ # matching_neighorhood_score_t_cur_with_t_minus_1[track_t_cur == cell]=score
1781
+ # else:
1782
+ # cells_present_in_t_cur_but_absent_in_t_minus_1.append(cell)
1783
+ # cells_present_in_t_cur_but_absent_in_t_minus_1_score[cell] = 0
1784
+
1785
+ # offer solutions based on scores --> TODO
1786
+
1787
+ # do I have a bug here ???
1788
+
1789
+ print(type(cells_and_their_neighbors_cur), type(
1790
+ cells_and_their_neighbors_minus_1)) # le second est une liste mais ne devrait pas !!!! --> un bug qq part
1791
+ # test after optimization
1792
+
1793
+ # ça rend le code un peu plus long mais vraiment pas deconnant --> doit etre assez facile à faire
1794
+ lab_t_minus_1 = label(track_t_minus_1, connectivity=1, background=0xFFFFFF)
1795
+ rps_t_minus_1 = regionprops(lab_t_minus_1)
1796
+ lab_t_cur = label(track_t_cur, connectivity=1, background=0xFFFFFF)
1797
+ rps_t_cur = regionprops(lab_t_cur)
1798
+ lab_t_plus_1 = label(track_t_plus_1, connectivity=1, background=0xFFFFFF)
1799
+ rps_t_plus_1 = regionprops(lab_t_plus_1)
1800
+
1801
+ # can I read all the neighbors in a smart way now by first index of one
1802
+
1803
+ # can compare neigbors for a cell in two instances --> give it a try
1804
+ # all should be easy I guess !!!
1805
+
1806
+ # 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
1807
+ # pb if a cell has no vertex it will be ignored
1808
+ # --> purely isolated cell
1809
+
1810
+ # in fact I can simply do unique otherwise directly on the image
1811
+
1812
+ cells_in_t_plus_1 = np.unique(track_t_plus_1)
1813
+ cells_in_t_cur, first_pixels_t_cur = get_cells_in_image_n_fisrt_pixel(track_t_cur) # np.unique(track_t_cur)
1814
+ cells_in_t_minus_1 = np.unique(track_t_minus_1)
1815
+
1816
+ map_tracks_n_label_t_cur = map_track_id_to_label(first_pixels_t_cur, track_t_cur, lab_t_cur)
1817
+
1818
+ print('first_pixels_t_cur', first_pixels_t_cur) # this is the ravel index --> how can I convert it back ???
1819
+ print('cells_in_t_cur', cells_in_t_cur)
1820
+ print('map_tracks_n_label_t_cur', map_tracks_n_label_t_cur)
1821
+
1822
+ # I'm ready to use this for the tracking of cells
1823
+ # just see how fast and efficient this is
1824
+ # do two versions, one with just showing errors and letting the user fix them and one with other
1825
+ if FIX_SWAPS:
1826
+ # DETECT SWAPS AND FIX THEM AND COMPUTE SCORE --> TODO also fix cell correspondance then --> really necessary!!!
1827
+ # we update both the cells and their local correspondance --> I think I have it --> just need few more crosses to identify more errors
1828
+ # 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
1829
+
1830
+ cells_and_their_neighbors_cur, map_tracks_n_label_t_cur, last_score_reached = optimize_score(
1831
+ cells_and_their_neighbors_cur, cells_and_their_neighbors_minus_1,
1832
+ cells_present_in_t_cur_but_absent_in_t_minus_1_score, map_tracks_n_label_t_cur)
1833
+ # print('map_tracks_n_label_t_cur2',map_tracks_n_label_t_cur2)
1834
+ # print('map_tracks_n_label_t_cur',map_tracks_n_label_t_cur)
1835
+
1836
+ # 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
1837
+ # 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
1838
+ # but still i need that
1839
+ # do a version of the tracking using pyramidal reg that relies on that!!! --> TODO
1840
+
1841
+ # possible assignment 10240303 6824721 0.6666666666666666 (156, 65, 47) (104, 35, 17) 0.6666666666666666 --> a dividing cell --> really a good peak
1842
+ # 0
1843
+ # 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é...
1844
+ # 0
1845
+ # 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
1846
+ # 0
1847
+ # possible assignment 12248378 7043456 1.0 (186, 229, 58) (107, 121, 128) 1.0 --> mis tracked cell
1848
+
1849
+ # cells_in_t_cur = cells_and_their_neighbors_cur.keys()
1850
+
1851
+ # TO MANUALLY FIND A CELL
1852
+ # for jjj, missing in enumerate(cells_in_t_cur):
1853
+ # if missing == 0xFFFFFF:
1854
+ # continue
1855
+ #
1856
+ # # if missing != r_g_b_to_rgb( 4,77,109):# for sure it's a swapped cell
1857
+ # # continue
1858
+ #
1859
+ # # the cell 9829855 is not shown properly --> it has no score --> why ?? maybe because no vx ???
1860
+ # if missing == 10369245:# 11560212
1861
+ # label_id = map_tracks_n_label_t_cur[jjj][1]
1862
+ # rps = rps_t_cur[label_id - 1]
1863
+ # bbox = rps.bbox
1864
+ # # bbox = [bbox[0] - 50, bbox[1] - 50, bbox[2] + 50, bbox[3] + 50]
1865
+ # # Bounding box ``(min_row, min_col, max_row, max_col)
1866
+ # # do a crop of the region of interest
1867
+ #
1868
+ # print('bbox pos of cell to assign' ,bbox)
1869
+
1870
+ # plot change
1871
+
1872
+ # 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())
1873
+ # False False True True --> ok in fact
1874
+
1875
+ compute_neighbor_score(cells_and_their_neighbors_cur, cells_and_their_neighbors_minus_1,
1876
+ cells_present_in_t_cur_but_absent_in_t_minus_1,
1877
+ cells_present_in_t_cur_but_absent_in_t_minus_1_score,
1878
+ matching_neighorhood_score_t_cur_with_t_minus_1, track_t_cur)
1879
+
1880
+ # plt.imshow(matching_neighorhood_score_t_cur_with_t_minus_1)
1881
+ # plt.show()
1882
+
1883
+ # if I really need swap then I also need
1884
+
1885
+ # for all
1886
+ print('cells_present_in_t_cur_but_absent_in_t_minus_1', cells_present_in_t_cur_but_absent_in_t_minus_1)
1887
+ print('cells_present_in_t_cur_but_absent_in_t_plus_1', cells_present_in_t_cur_but_absent_in_t_plus_1)
1888
+
1889
+ print('total score before optimization',
1890
+ sum(cells_present_in_t_cur_but_absent_in_t_minus_1_score.values())) # 305.82 initially then
1891
+ # for all cells with low score if they are try a swapping but only if present before
1892
+
1893
+ # NB I HAVE FOUND A SWAPPED CELL --> 37,51, 138 located at 437, 487 in 0
1894
+ # I need map one to one the label id and the track id!!!
1895
+ # anyways that is very useful
1896
+
1897
+ # need map track to the label image at least for the current but also for the two others and need be able to get the coords from that !!!!
1898
+
1899
+ # TODO see if I can improve score between -1 and 0 by swapping
1900
+ # see how fast/slow this could be --> just restrict myself to cells with low
1901
+
1902
+ # TODO find swaps that maximize score
1903
+
1904
+ # compute sum score and as long as it improves --> continue
1905
+
1906
+ # remove purewhite from this array
1907
+ for jjj, missing in enumerate(cells_in_t_cur):
1908
+ if missing == 0xFFFFFF:
1909
+ continue
1910
+
1911
+ # if missing != r_g_b_to_rgb( 4,77,109):# for sure it's a swapped cell
1912
+ # continue
1913
+
1914
+ # the cell 9829855 is not shown properly --> it has no score --> why ?? maybe because no vx ???
1915
+ if False:
1916
+ if missing == 9829855:
1917
+ # indeed this is an isolated cell that has one or no vertices --> really need handle that at some point but ok for now
1918
+ label_id = map_tracks_n_label_t_cur[jjj][1]
1919
+ rps = rps_t_cur[label_id - 1]
1920
+ bbox = rps.bbox
1921
+ # bbox = [bbox[0] - 50, bbox[1] - 50, bbox[2] + 50, bbox[3] + 50]
1922
+ # Bounding box ``(min_row, min_col, max_row, max_col)
1923
+ # do a crop of the region of interest
1924
+
1925
+ print(bbox)
1926
+ try:
1927
+
1928
+ plot_n_images_in_line(int24_to_RGB(track_t_minus_1[bbox[0]:bbox[2], bbox[1]:bbox[3]]),
1929
+ int24_to_RGB(track_t_cur[bbox[0]:bbox[2], bbox[1]:bbox[3]]),
1930
+ int24_to_RGB(track_t_plus_1[bbox[0]:bbox[2], bbox[1]:bbox[3]]),
1931
+ matching_neighorhood_score_t_cur_with_t_minus_1[bbox[0]:bbox[2],
1932
+ bbox[1]:bbox[3]],
1933
+ matching_neighorhood_score_t_cur_with_t_plus_1[bbox[0]:bbox[2],
1934
+ bbox[1]:bbox[3]],
1935
+ title='bug' + str(r_g_b_from_rgb(missing)))
1936
+ except:
1937
+ traceback.print_exc()
1938
+ print('diplay error --> ifnore for naow')
1939
+
1940
+ try:
1941
+ decision = take_decision(missing, cells_and_their_neighbors_minus_1, cells_and_their_neighbors_cur,
1942
+ cells_and_their_neighbors_plus_1,
1943
+ cells_present_in_t_cur_but_absent_in_t_minus_1_score,
1944
+ cells_present_in_t_cur_but_absent_in_t_plus_1_score,
1945
+ assume_previous_image_is_GT=True)
1946
+ except:
1947
+ traceback.print_exc()
1948
+ print('pb with decision --> contuinuing but need a fix some day !!!')
1949
+ continue
1950
+
1951
+ print(missing, ' --> ', decision) # decide whether to keep or discard a cell
1952
+
1953
+ # division
1954
+ # death
1955
+ # ignore
1956
+ # None
1957
+
1958
+ # see unhandled cases
1959
+
1960
+ # cell 4,77,109 is clearly swapped --> can I detect it and fix it in a smart way ?????
1961
+
1962
+ # if decision is None: # --> a lot of these are artifacts --> see how to fix??? or ignore or have mire stringent rules
1963
+ # if decision is not None and death in decision:
1964
+ # there is a bug somewhere !!!
1965
+ # if decision is not None and not ignore in decision:
1966
+ # if decision is not None and (ignore in decision and (cells_present_in_t_cur_but_absent_in_t_minus_1_score[missing] != 1 or cells_present_in_t_cur_but_absent_in_t_plus_1_score[missing] != 1)): # cells ignore due to sensitivity
1967
+
1968
+ # nb some of the local swap are above 0.5 (maybe it's due to my test sample because I swapped big cells which is unlikely to happen)
1969
+ #
1970
+ # shall I start by trying to maximize score for all the cells below or equal 0.5 then do the rest of the code
1971
+ # most likely swapped cells would have to
1972
+
1973
+ # if score of one is 0 --> probably a far away swap in the track in the current frame --> need fix it
1974
+ # if first score is 0 --> probably a far away swap in the track in the current frame --> need fix it in current
1975
+ if decision is None and ((cells_present_in_t_cur_but_absent_in_t_minus_1_score[missing] < 0.5 or
1976
+ cells_present_in_t_cur_but_absent_in_t_plus_1_score[missing] < 0.5)):
1977
+ # label_id = np.argwhere(map_tracks_n_label_t_cur[0]==missing)
1978
+
1979
+ print('decision scores', cells_present_in_t_cur_but_absent_in_t_minus_1_score[missing],
1980
+ cells_present_in_t_cur_but_absent_in_t_plus_1_score[missing])
1981
+
1982
+ label_id = map_tracks_n_label_t_cur[jjj][1]
1983
+
1984
+ # for val in map_tracks_n_label_t_cur[0]:
1985
+ # if val == missing:
1986
+ # print('found')
1987
+ # break
1988
+ # en effet ça n'y est pas mais pkoi
1989
+
1990
+ # why is cell not found ??
1991
+ # this is not what it's supposed to be
1992
+ # try:
1993
+
1994
+ print(missing, '--> ', r_g_b_from_rgb(missing))
1995
+ print(map_tracks_n_label_t_cur.shape)
1996
+ # why empty ???? --> should not be so!!!
1997
+ print(label_id)
1998
+ # print('track_t_cur==missing',track_t_cur==missing,'track_t_cur==missing')
1999
+ # check that I have no bug otherwise it will be complex
2000
+ rps = rps_t_cur[label_id - 1]
2001
+ bbox = rps.bbox
2002
+ bbox = [bbox[0] - 50, bbox[1] - 50, bbox[2] + 50, bbox[3] + 50]
2003
+ # Bounding box ``(min_row, min_col, max_row, max_col)
2004
+ # do a crop of the region of interest
2005
+
2006
+ print(bbox)
2007
+ try:
2008
+
2009
+ plot_n_images_in_line(int24_to_RGB(track_t_minus_1[bbox[0]:bbox[2], bbox[1]:bbox[3]]),
2010
+ int24_to_RGB(track_t_cur[bbox[0]:bbox[2], bbox[1]:bbox[3]]),
2011
+ int24_to_RGB(track_t_plus_1[bbox[0]:bbox[2], bbox[1]:bbox[3]]),
2012
+ matching_neighorhood_score_t_cur_with_t_minus_1[bbox[0]:bbox[2],
2013
+ bbox[1]:bbox[3]],
2014
+ matching_neighorhood_score_t_cur_with_t_plus_1[bbox[0]:bbox[2],
2015
+ bbox[1]:bbox[3]], title=str(decision) + ' ' + str(r_g_b_from_rgb(missing)))
2016
+ except:
2017
+ traceback.print_exc()
2018
+ print('diplay error --> ifnore for naow')
2019
+ # except:
2020
+ # pass
2021
+ # TODO get the region of the cell and crop the image so that I can see it
2022
+ # I could crop the image
2023
+
2024
+ # would be great to see the cells just to see if things are indeed ok and or fix the stuff otherwise
2025
+
2026
+ # show and center on cell
2027
+
2028
+ # start from cells with lowest score and then progressively go up
2029
+ # by default new cells will have the lowest score they are either overseg in current or non segmented cells in previous, if we assume that the first image is good, perfectly corrected then the cell is definitely an overseg in cur
2030
+ # TODO do a brain that takes decision
2031
+ # the brain could also generate various options
2032
+
2033
+ # cells_and_their_neighbors_minus_1 = associate_cells_to_neighbors_ID_in_dict(cells_and_their_neighbors_minus_1)
2034
+ # cells_and_their_neighbors_cur = associate_cells_to_neighbors_ID_in_dict(cells_and_their_neighbors_cur)
2035
+ # cells_and_their_neighbors_plus_1
2036
+
2037
+ # TODO I could try to reidentify swapped cells --> by default they should be close
2038
+ # TO MAP THE CELL I COULD USE THE TRANSLATION BETWEEN THE TWO IMAGES BASED ON ITS NEIGHBOR CELLS TO IDENTIFY IT BACK --> VERY SMART IDEA AND SO EASY TO IMPLEMENT
2039
+ # --> TODO MAYBE CHECK AND DO THIS CODE
2040
+ # AS LONG AS I IMPROVE SCORE I CAN CONTINUE SWAPPING
2041
+ # I NEED CHANGE THE ID IN THE CURRENT CELL AND ALL ITS NEIGHBORS
2042
+ # WHEN I THINK I HAVE IDENTIFIED A SWAPPING I NEED CHECK JUST IN THE NEIGHBORHOOD --> ONE OR TWO ROWS AROUND THE LOST CELL --> VERY GOOD IDEA IN FACT
2043
+
2044
+ # need two mappings --> one on orig and one on tracking --> fairly good idea in fact!!!
2045
+ # je pense que le neighborhood est la solution
2046
+
2047
+ # ça marche pas mal --> ça attire l'attention sur les cellules qui changent de voisin --> marche plutot bien en fait !!!
2048
+ # low score can be due to a division or to a new cell
2049
+ # if cell has low score and is adjacent to a new cell then most likely a division
2050
+ # else this can highlight T1s indeirectly !!!
2051
+
2052
+ # maybe if this is combined to lost cells and smart algo I can reach something really magic
2053
+ # TODO --> do compare all --> TODO --> REALLY FAST !!!
2054
+ # this is really good because it can also identify swapping whereas the other algos cannot --> try combine this to other to differentiate swapping from other features and maybe use this to identify death and divisions
2055
+ # TODO finish that soon
2056
+
2057
+ # when match is poor --> try find best match
2058
+
2059
+ # compute a score for every cell --> shall I reconvert it to a dict to ease the comparison ????
2060
+ # or create
2061
+
2062
+ plot_n_images_in_line(int24_to_RGB(track_t_minus_1), int24_to_RGB(track_t_cur), int24_to_RGB(track_t_plus_1),
2063
+ matching_neighorhood_score_t_cur_with_t_minus_1,
2064
+ matching_neighorhood_score_t_cur_with_t_plus_1)
2065
+
2066
+ # in some case it can be useful to check even more frames
2067
+ # for example
2068
+
2069
+ # this can also be done using label and regionprops --> see what is the best choice for this
2070
+ # in a way I could get properties only of the interesting cells
2071
+ # check the intersections I need
2072
+
2073
+ # overseg is smthg that is present on the middle frame and not on the one before and after
2074
+ # an underseg is something that is absent from middle image and present in the two others # pb is that since tracks don't match I will not necessarily detect it but I may be able to detect it based on neighborhood but the algo need be super smart --> see if I can find a way to do that !!!
2075
+
2076
+ # underseg could be smthg present in the two fisrt and not in the last --> but some apoptotic cells would be misidentified --> also these errors most likely require human intervention
2077
+ # could do a code that follows the error and lets the user decide what TODO
2078
+ # check also swappings and see if I can fix them!!!!
2079
+
2080
+ # I could pass underseg to the next
2081
+ # can I identify a cell based on its neighbors --> most likely yes and if so I should be able to fix most errors --> provided there are little errors
2082
+
2083
+ # print missing between consecutive frames
2084
+ missing_between_t_cur_and_t_minus_1 = np.setdiff1d(track_t_cur, track_t_minus_1) # potentially underseg
2085
+ missing_between_t_cur_and_t_plus_1 = np.setdiff1d(track_t_cur, track_t_plus_1) # potentially overeseg
2086
+
2087
+ # these are true overseg
2088
+ overseg_t_cur = np.intersect1d(missing_between_t_cur_and_t_minus_1,
2089
+ missing_between_t_cur_and_t_plus_1)
2090
+
2091
+ # can I also get infos from partial intersections between two consecutive frames --> most likely yes
2092
+ # for example if a cell is newly appearing in last and absent in the middle and if its neigbors match that in the first then there is likely to be an underseg that need be fixed !!!
2093
+ # check and reimplement my swapping algo to see how I can deal with that
2094
+
2095
+ # do checks only if things are missing or if some pbs are encountered --> if so --> then fix them!!!
2096
+
2097
+ # NB IN FACT AN OVERSEG IN CUR CAN BE DUE TO AN UNDERSEG IN PREVIOUS --> KEEP IN MIND AND TRY TO DESIGN SOME SUPRA INTELLIGENT CODE TO FIX THAT!!!
2098
+
2099
+ # ça a l'air de marcher mais faut vraiment que le tracking soit perfect --> see how
2100
+ # maybe I can do an hybrid correction where the soft detects the error but the user is asked to fix it or to chose between automated solutions --> TODO !!!
2101
+ print('overseg_t_cur', overseg_t_cur)
2102
+ # qd meme ça marche pas mal!!!!
2103
+
2104
+ # TODO try show the overseg cells or save them so that I can check by myself
2105
+ # do a plotter that plots 3 images + the ovgerseg cells
2106
+
2107
+ # in fact I may have smarter rules --> for example if something is present in two consecutive images it is likely to be present in the previous one too!!!
2108
+ # see the best way TODO that
2109
+ # TODO also identify swappings
2110
+
2111
+ overseg_mask = np.zeros_like(track_t_cur)
2112
+ overseg_mask[track_t_cur == 0xFFFFFF] = 64
2113
+
2114
+ for missing in overseg_t_cur:
2115
+ overseg_mask[track_t_cur == missing] = 255
2116
+
2117
+ for missing in missing_between_t_cur_and_t_minus_1:
2118
+ overseg_mask[track_t_cur == missing] = 128
2119
+
2120
+ for missing in missing_between_t_cur_and_t_minus_1:
2121
+ overseg_mask[
2122
+ track_t_cur == missing] = 192 # practically these are all the same cells as in overseg_t_cur --> DO I HAVE A BUG ????
2123
+
2124
+ # ça parait realiste mais checker usr un vrai example avec 3 images
2125
+
2126
+ # plt.imshow(overseg_mask)
2127
+ # plt.show()
2128
+ plot_n_images_in_line(int24_to_RGB(track_t_minus_1), int24_to_RGB(track_t_cur), int24_to_RGB(track_t_plus_1),
2129
+ overseg_mask)
2130
+
2131
+ underseg_mask = np.zeros_like(track_t_cur)
2132
+
2133
+ # print missing between consecutive frames
2134
+
2135
+ # nb also don't forget that the intersections can be done both ways and that some info is stored in there too !!! --> TODO do fix all!!!
2136
+ lost_cells_between_t_minus_1_and_current = np.setdiff1d(track_t_minus_1, track_t_cur) # potentially underseg
2137
+ lost_cells_between_t_plus_1_and_current = np.setdiff1d(track_t_plus_1, track_t_cur) # potentially overeseg
2138
+
2139
+ for missing in lost_cells_between_t_minus_1_and_current:
2140
+ underseg_mask[track_t_minus_1 == missing] = 255
2141
+
2142
+ for missing in lost_cells_between_t_plus_1_and_current:
2143
+ underseg_mask[track_t_plus_1 == missing] = 128
2144
+
2145
+ underseg_mask[track_t_cur == 0xFFFFFF] = 64
2146
+
2147
+ # there is indeed important infos in that too
2148
+ # if cells do really match well --> then I could check them for sure
2149
+
2150
+ # shall I try a resegmentation !!!
2151
+
2152
+ # TODO maybe take a simpler example than in the ovipo because it's too complex
2153
+
2154
+ # ça parait realiste mais checker usr un vrai example avec 3 images
2155
+
2156
+ # plt.imshow(overseg_mask)
2157
+ # plt.show()
2158
+ plot_n_images_in_line(int24_to_RGB(track_t_minus_1), int24_to_RGB(track_t_cur), int24_to_RGB(track_t_plus_1),
2159
+ underseg_mask)
2160
+
2161
+ # these are true overseg
2162
+ # overseg_t_cur = np.intersect1d(missing_between_t_cur_and_t_minus_1,
2163
+ # missing_between_t_cur_and_t_plus_1)
2164
+
2165
+ # should I care about the common cells --> yes maybe if they do not share the same neighbors --> in that case this most likely means they are swapped -->
2166
+
2167
+ # then I could fix them
2168
+ # in fact I could detect neighborhood only for the common cells to see if ok
2169
+ #
2170
+
2171
+ #
2172
+ #
2173
+ # print(overseg_t_cur)
2174
+ #
2175
+ # common_cells = np.intersect1d(cells_in_current, cells_in_prev)
2176
+ # print(common_cells)
2177
+ # # print("Unique values in array1 that are not in array2:")
2178
+ # lost_cells =np.setdiff1d(cells_in_current, cells_in_prev)
2179
+ # print(lost_cells)
2180
+
2181
+ # that is ok all of this is super fast --> now try to do it for real and for the magic of it
2182
+
2183
+ # maybe also store seg/labels so that I don't need redo them
2184
+ # for all diverging cells I could check them and do all sorts to stuff with them
2185
+
2186
+ # can I correct for swapping too
2187
+
2188
+ # not bad --> I could then see if the cell comes back or vanishes
2189
+ # I could maybe compare neighbours TODO magics
2190
+
2191
+ # TODO --> see what I can do with that !!!
2192
+
2193
+ # lost cells and new cells
2194
+
2195
+ # pas mal en fait
2196
+
2197
+ # avec ça je dois avoir à peu pres tout ce que je veux
2198
+
2199
+ # maybe get bonds coords too using coords rather than images --> in a way that is a good idea
2200
+
2201
+ # TODO maybe also associate bonds to cells --> can eb useful and not that hard to do --> then I have evrything to do my desired code
2202
+
2203
+ #
2204
+
2205
+ # not bad in fact generate all the things I need and just get the desired output
2206
+
2207
+ # really not bad !!!
2208
+
2209
+ # ou bien associer les neighbors à une cellule
2210
+
2211
+ # loop pour chaque cellule
2212
+
2213
+ # nb one can call a numba function this way --> very easy in fact
2214
+ # sum_array_numba = jit()(sum_array)
2215
+
2216
+ # plt.imshow(vertices)
2217
+ # plt.show()
2218
+ # bonds = find_bonds(img) # chaque passage double le temps --> a faire que si necessaire donc
2219
+ # plt.imshow(bonds)
2220
+ # plt.show()
2221
+
2222
+ # we do have our three files --> generate something useful out of them
2223
+ #
2224
+ # for file_to_read in files_to_read:
2225
+ # try:
2226
+ # tracked_cells_resized, TA_path = smart_name_parser(file_to_read, ordered_output=['TA', 'tracked_cells_resized.png'])
2227
+ # except:
2228
+ # tracked_cells_resized = TA_path = None
2229
+ # print(tracked_cells_resized, TA_path)
2230
+
2231
+ print('files are useful', files_to_read)
2232
+
2233
+ # TODO very dirty --> clean it but very powerful!!!
2234
+ def createTAmask(orig, mask):
2235
+ # if len(orig.shape)!=3:
2236
+ # print(orig)
2237
+ red =orig[...,0]
2238
+ red[mask[...,0]!=0]=255
2239
+ orig[...,0]=red
2240
+ return orig
2241
+
2242
+ # TODO
2243
+ def help_user_correct_errors(files, channel=None, progress_callback=None):
2244
+ for iii in range(len(files)):
2245
+
2246
+ try:
2247
+ if early_stop.stop:
2248
+ return
2249
+ if progress_callback is not None:
2250
+ progress_callback.emit(int((iii / len(files)) * 100))
2251
+ else:
2252
+ print(str((iii / len(files)) * 100) + '%')
2253
+ except:
2254
+ pass
2255
+
2256
+ # file_t0 = files[iii-1]
2257
+ # file_t1 = files[iii]
2258
+ #
2259
+ # print(file_t0, file_t1)
2260
+
2261
+ # TODO instead of getting 3 files --> just make it able to get n files with specific rules --> TODO
2262
+ files_to_read = get_n_files_from_list(files, iii, -1, 1)
2263
+ # print(files_to_read)
2264
+
2265
+ # TODO handle first ad last
2266
+
2267
+ if files_to_read[0] is None or files_to_read[len(files_to_read) - 1] is None:
2268
+ # first or last image missing --> skipping for now but generate code at some point
2269
+ print('missing files', files_to_read)
2270
+
2271
+ # in fact here I could make use of the data of two consecutive images
2272
+ # or should I try directly with 3 images ????
2273
+
2274
+ # think about it
2275
+ continue
2276
+
2277
+ # for file_to_read in files_to_read:
2278
+ extension = '.tif' # '.png' # '.tif' # '.png' # '.tif'
2279
+ TA_path_minus_1, track_t_minus_1 = smart_name_parser(files_to_read[0],
2280
+ ordered_output=['TA', 'tracked_cells_resized' + extension])
2281
+ TA_path_cur, track_t_cur = smart_name_parser(files_to_read[1],
2282
+ ordered_output=['TA', 'tracked_cells_resized' + extension])
2283
+ TA_path_plus_1, track_t_plus_1 = smart_name_parser(files_to_read[2],
2284
+ ordered_output=['TA', 'tracked_cells_resized' + extension])
2285
+
2286
+ # print(tracked_cells_resized)
2287
+ track_t_minus_1 = RGB_to_int24(Img(track_t_minus_1))
2288
+ track_t_cur = RGB_to_int24(Img(track_t_cur))
2289
+ track_t_plus_1 = RGB_to_int24(Img(track_t_plus_1))
2290
+
2291
+
2292
+ # show masks too
2293
+ _, handCorrection_t_minus_1 = smart_name_parser(files_to_read[0],
2294
+ ordered_output=['TA', 'handCorrection.tif'])
2295
+ _, handCorrection_t_cur = smart_name_parser(files_to_read[1],
2296
+ ordered_output=['TA', 'handCorrection.tif'])
2297
+ _, handCorrection_t_plus_1 = smart_name_parser(files_to_read[2],
2298
+ ordered_output=['TA', 'handCorrection.tif'])
2299
+
2300
+ TA_path_handCorrection_t_minus_1 =handCorrection_t_minus_1
2301
+ TA_path_handCorrection_t_cur=handCorrection_t_cur
2302
+ TA_path_handCorrection_t_plus_1=handCorrection_t_plus_1
2303
+
2304
+ # TODO really do the mask à la TA
2305
+ handCorrection_t_minus_1 = Img(handCorrection_t_minus_1)
2306
+ handCorrection_t_cur = Img(handCorrection_t_cur)
2307
+ handCorrection_t_plus_1 = Img(handCorrection_t_plus_1)
2308
+ if len(handCorrection_t_minus_1.shape)==3:
2309
+ handCorrection_t_minus_1=handCorrection_t_minus_1[...,0]
2310
+ if len(handCorrection_t_cur.shape)==3:
2311
+ handCorrection_t_cur=handCorrection_t_cur[...,0]
2312
+ if len(handCorrection_t_plus_1.shape)==3:
2313
+ handCorrection_t_plus_1=handCorrection_t_plus_1[...,0]
2314
+
2315
+ original_t_minus_1 = Img(files_to_read[0])
2316
+ original_t_cur = Img(files_to_read[1])
2317
+ original_t_plus_1 = Img(files_to_read[2])
2318
+
2319
+ if channel is not None:
2320
+ # we reensure image has channel otherwise skip
2321
+ if len(original_t_minus_1.shape) > 2:
2322
+ original_t_minus_1=original_t_minus_1[...,channel]
2323
+ if len(original_t_cur.shape) > 2:
2324
+ original_t_cur=original_t_cur[...,channel]
2325
+ if len(original_t_plus_1.shape) > 2:
2326
+ original_t_plus_1=original_t_plus_1[...,channel]
2327
+
2328
+
2329
+ # find_vertices(img)
2330
+
2331
+ # could compare this to the other
2332
+ # vertices_t_minus_1 = find_vertices(track_t_minus_1, return_vertices=True, return_bonds=False)
2333
+ # vertices_t_cur = find_vertices(track_t_cur, return_vertices=True, return_bonds=False)
2334
+ # vertices_t_plus_1 = find_vertices(track_t_plus_1, return_vertices=True, return_bonds=False)
2335
+ vertices_t_minus_1 = np.stack(np.where(track_t_minus_1 == 0xFFFFFF),axis=1) # find_vertices(track_t_minus_1, return_vertices=True, return_bonds=False)
2336
+ vertices_t_cur = np.stack(np.where(track_t_cur == 0xFFFFFF),axis=1) # find_vertices(track_t_cur, return_vertices=True, return_bonds=False)
2337
+ vertices_t_plus_1 = np.stack(np.where(track_t_plus_1 == 0xFFFFFF),axis=1) # find_vertices(track_t_plus_1, return_vertices=True, return_bonds=False)
2338
+
2339
+ # plt.imshow(vertices)
2340
+ # plt.show()
2341
+
2342
+ # print(get_vx_neighbors(vertices, RGB24img=img)) # is that slow??? --
2343
+
2344
+ # 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
2345
+
2346
+ # ce truc est slow --> can I speed up using vertices --> most likely yes
2347
+ # 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
2348
+ # 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
2349
+ # aussi voir comment associer les vertices à une seule cellule --> car très utile
2350
+ # print() # a bit faster indeed but not outstanding
2351
+
2352
+ # 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
2353
+ cells_and_their_neighbors_minus_1 = np.unique(
2354
+ np.asarray(associate_cell_to_its_neighbors2(vertices_t_minus_1, track_t_minus_1)), axis=0)
2355
+ cells_and_their_neighbors_cur = np.unique(
2356
+ np.asarray(associate_cell_to_its_neighbors2(vertices_t_cur, track_t_cur)), axis=0)
2357
+ cells_and_their_neighbors_plus_1 = np.unique(
2358
+ np.asarray(associate_cell_to_its_neighbors2(vertices_t_plus_1, track_t_plus_1)), axis=0)
2359
+
2360
+ cells_and_their_neighbors_minus_1 = associate_cells_to_neighbors_ID_in_dict(cells_and_their_neighbors_minus_1)
2361
+ cells_and_their_neighbors_cur = associate_cells_to_neighbors_ID_in_dict(cells_and_their_neighbors_cur)
2362
+ cells_and_their_neighbors_plus_1 = associate_cells_to_neighbors_ID_in_dict(cells_and_their_neighbors_plus_1)
2363
+
2364
+ # print('cells_and_their_neighbors_minus_1', cells_and_their_neighbors_minus_1)
2365
+ # print('cells_and_their_neighbors_cur', cells_and_their_neighbors_cur)
2366
+ # print('cells_and_their_neighbors_plus_1', cells_and_their_neighbors_plus_1)
2367
+
2368
+ # for all the common cells --> compute a score
2369
+ # nb of matching neighbs / total nb of neighbs in both
2370
+
2371
+ # create and color
2372
+
2373
+ cells_present_in_t_cur_but_absent_in_t_plus_1 = []
2374
+ cells_present_in_t_cur_but_absent_in_t_plus_1_score = {}
2375
+ matching_neighorhood_score_t_cur_with_t_plus_1 = np.zeros_like(track_t_cur, dtype=float)
2376
+
2377
+ compute_neighbor_score(cells_and_their_neighbors_cur, cells_and_their_neighbors_plus_1,
2378
+ cells_present_in_t_cur_but_absent_in_t_plus_1,
2379
+ cells_present_in_t_cur_but_absent_in_t_plus_1_score,
2380
+ matching_neighorhood_score_t_cur_with_t_plus_1, track_t_cur)
2381
+
2382
+ # for cell, neigbs in cells_and_their_neighbors_cur.items():
2383
+ # if cell in cells_and_their_neighbors_plus_1:
2384
+ # # compute score and color cell
2385
+ # neigbsb = cells_and_their_neighbors_plus_1[cell]
2386
+ # score = (len(list(set(neigbs) & set(neigbsb))) * 2) / (len(neigbsb) + len(neigbs))
2387
+ # cells_present_in_t_cur_but_absent_in_t_plus_1_score[cell]=score
2388
+ # matching_neighorhood_score_t_cur_with_t_plus_1[track_t_cur == cell] = score
2389
+ # else:
2390
+ # cells_present_in_t_cur_but_absent_in_t_plus_1.append(cell)
2391
+ # cells_present_in_t_cur_but_absent_in_t_plus_1_score[cell] = 0
2392
+
2393
+ cells_present_in_t_cur_but_absent_in_t_minus_1 = []
2394
+ cells_present_in_t_cur_but_absent_in_t_minus_1_score = {}
2395
+ matching_neighorhood_score_t_cur_with_t_minus_1 = np.zeros_like(track_t_cur, dtype=float)
2396
+
2397
+ compute_neighbor_score(cells_and_their_neighbors_cur, cells_and_their_neighbors_minus_1,
2398
+ cells_present_in_t_cur_but_absent_in_t_minus_1,
2399
+ cells_present_in_t_cur_but_absent_in_t_minus_1_score,
2400
+ matching_neighorhood_score_t_cur_with_t_minus_1, track_t_cur)
2401
+ # for cell, neigbs in cells_and_their_neighbors_cur.items():
2402
+ # if cell in cells_and_their_neighbors_minus_1:
2403
+ # # compute score and color cell
2404
+ # neigbsb=cells_and_their_neighbors_minus_1[cell]
2405
+ # score = (len(list(set(neigbs) & set(neigbsb)))*2)/(len(neigbsb)+len(neigbs))
2406
+ # cells_present_in_t_cur_but_absent_in_t_minus_1_score[cell]=score
2407
+ # matching_neighorhood_score_t_cur_with_t_minus_1[track_t_cur == cell]=score
2408
+ # else:
2409
+ # cells_present_in_t_cur_but_absent_in_t_minus_1.append(cell)
2410
+ # cells_present_in_t_cur_but_absent_in_t_minus_1_score[cell] = 0
2411
+
2412
+ # offer solutions based on scores --> TODO
2413
+
2414
+ # do I have a bug here ???
2415
+
2416
+ # 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
2417
+ # test after optimization
2418
+
2419
+ # ça rend le code un peu plus long mais vraiment pas deconnant --> doit etre assez facile à faire
2420
+ # lab_t_minus_1 = label(track_t_minus_1, connectivity=1, background=0xFFFFFF)
2421
+ # rps_t_minus_1 = regionprops(lab_t_minus_1)
2422
+ # lab_t_cur = label(track_t_cur, connectivity=1, background=0xFFFFFF)
2423
+ # rps_t_cur = regionprops(lab_t_cur)
2424
+ # lab_t_plus_1 = label(track_t_plus_1, connectivity=1, background=0xFFFFFF)
2425
+ # rps_t_plus_1 = regionprops(lab_t_plus_1)
2426
+
2427
+ # can I read all the neighbors in a smart way now by first index of one
2428
+
2429
+ # can compare neigbors for a cell in two instances --> give it a try
2430
+ # all should be easy I guess !!!
2431
+
2432
+ # 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
2433
+ # pb if a cell has no vertex it will be ignored
2434
+ # --> purely isolated cell
2435
+
2436
+ # in fact I can simply do unique otherwise directly on the image
2437
+
2438
+ # cells_in_t_plus_1 = np.unique(track_t_plus_1)
2439
+ # cells_in_t_cur, first_pixels_t_cur = get_cells_in_image_n_fisrt_pixel(track_t_cur) # np.unique(track_t_cur)
2440
+ # cells_in_t_minus_1 = np.unique(track_t_minus_1)
2441
+ #
2442
+ # map_tracks_n_label_t_cur = map_track_id_to_label(first_pixels_t_cur, track_t_cur, lab_t_cur)
2443
+ #
2444
+ # print('first_pixels_t_cur', first_pixels_t_cur) # this is the ravel index --> how can I convert it back ???
2445
+ # print('cells_in_t_cur', cells_in_t_cur)
2446
+ # print('map_tracks_n_label_t_cur', map_tracks_n_label_t_cur)
2447
+ #
2448
+ # # I'm ready to use this for the tracking of cells
2449
+ # # just see how fast and efficient this is
2450
+ # # do two versions, one with just showing errors and letting the user fix them and one with other
2451
+ # if FIX_SWAPS:
2452
+ # # DETECT SWAPS AND FIX THEM AND COMPUTE SCORE --> TODO also fix cell correspondance then --> really necessary!!!
2453
+ # # we update both the cells and their local correspondance --> I think I have it --> just need few more crosses to identify more errors
2454
+ # # 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
2455
+ #
2456
+ # cells_and_their_neighbors_cur, map_tracks_n_label_t_cur, last_score_reached = optimize_score(
2457
+ # cells_and_their_neighbors_cur, cells_and_their_neighbors_minus_1,
2458
+ # cells_present_in_t_cur_but_absent_in_t_minus_1_score, map_tracks_n_label_t_cur)
2459
+ # # print('map_tracks_n_label_t_cur2',map_tracks_n_label_t_cur2)
2460
+ # # print('map_tracks_n_label_t_cur',map_tracks_n_label_t_cur)
2461
+ #
2462
+ # # 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
2463
+ # # 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
2464
+ # # but still i need that
2465
+ # # do a version of the tracking using pyramidal reg that relies on that!!! --> TODO
2466
+ #
2467
+ # # possible assignment 10240303 6824721 0.6666666666666666 (156, 65, 47) (104, 35, 17) 0.6666666666666666 --> a dividing cell --> really a good peak
2468
+ # # 0
2469
+ # # 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é...
2470
+ # # 0
2471
+ # # 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
2472
+ # # 0
2473
+ # # possible assignment 12248378 7043456 1.0 (186, 229, 58) (107, 121, 128) 1.0 --> mis tracked cell
2474
+ #
2475
+ # # cells_in_t_cur = cells_and_their_neighbors_cur.keys()
2476
+ #
2477
+ # # TO MANUALLY FIND A CELL
2478
+ # # for jjj, missing in enumerate(cells_in_t_cur):
2479
+ # # if missing == 0xFFFFFF:
2480
+ # # continue
2481
+ # #
2482
+ # # # if missing != r_g_b_to_rgb( 4,77,109):# for sure it's a swapped cell
2483
+ # # # continue
2484
+ # #
2485
+ # # # the cell 9829855 is not shown properly --> it has no score --> why ?? maybe because no vx ???
2486
+ # # if missing == 10369245:# 11560212
2487
+ # # label_id = map_tracks_n_label_t_cur[jjj][1]
2488
+ # # rps = rps_t_cur[label_id - 1]
2489
+ # # bbox = rps.bbox
2490
+ # # # bbox = [bbox[0] - 50, bbox[1] - 50, bbox[2] + 50, bbox[3] + 50]
2491
+ # # # Bounding box ``(min_row, min_col, max_row, max_col)
2492
+ # # # do a crop of the region of interest
2493
+ # #
2494
+ # # print('bbox pos of cell to assign' ,bbox)
2495
+ #
2496
+ # # plot change
2497
+ #
2498
+ # # 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())
2499
+ # # False False True True --> ok in fact
2500
+ #
2501
+ # compute_neighbor_score(cells_and_their_neighbors_cur, cells_and_their_neighbors_minus_1,
2502
+ # cells_present_in_t_cur_but_absent_in_t_minus_1,
2503
+ # cells_present_in_t_cur_but_absent_in_t_minus_1_score,
2504
+ # matching_neighorhood_score_t_cur_with_t_minus_1, track_t_cur)
2505
+ #
2506
+ # # plt.imshow(matching_neighorhood_score_t_cur_with_t_minus_1)
2507
+ # # plt.show()
2508
+ #
2509
+ # # if I really need swap then I also need
2510
+
2511
+ # for all
2512
+ # print('cells_present_in_t_cur_but_absent_in_t_minus_1', cells_present_in_t_cur_but_absent_in_t_minus_1)
2513
+ # print('cells_present_in_t_cur_but_absent_in_t_plus_1', cells_present_in_t_cur_but_absent_in_t_plus_1)
2514
+ #
2515
+ # print('total score before optimization',
2516
+ # sum(cells_present_in_t_cur_but_absent_in_t_minus_1_score.values())) # 305.82 initially then
2517
+ # for all cells with low score if they are try a swapping but only if present before
2518
+
2519
+ # NB I HAVE FOUND A SWAPPED CELL --> 37,51, 138 located at 437, 487 in 0
2520
+ # I need map one to one the label id and the track id!!!
2521
+ # anyways that is very useful
2522
+
2523
+ # need map track to the label image at least for the current but also for the two others and need be able to get the coords from that !!!!
2524
+
2525
+ # TODO see if I can improve score between -1 and 0 by swapping
2526
+ # see how fast/slow this could be --> just restrict myself to cells with low
2527
+
2528
+ # TODO find swaps that maximize score
2529
+
2530
+ # compute sum score and as long as it improves --> continue
2531
+
2532
+ # remove purewhite from this array
2533
+ # for jjj, missing in enumerate(cells_in_t_cur):
2534
+ # if missing == 0xFFFFFF:
2535
+ # continue
2536
+ #
2537
+ # # if missing != r_g_b_to_rgb( 4,77,109):# for sure it's a swapped cell
2538
+ # # continue
2539
+ #
2540
+ # # the cell 9829855 is not shown properly --> it has no score --> why ?? maybe because no vx ???
2541
+ # if False:
2542
+ # if missing == 9829855:
2543
+ # # indeed this is an isolated cell that has one or no vertices --> really need handle that at some point but ok for now
2544
+ # label_id = map_tracks_n_label_t_cur[jjj][1]
2545
+ # rps = rps_t_cur[label_id - 1]
2546
+ # bbox = rps.bbox
2547
+ # # bbox = [bbox[0] - 50, bbox[1] - 50, bbox[2] + 50, bbox[3] + 50]
2548
+ # # Bounding box ``(min_row, min_col, max_row, max_col)
2549
+ # # do a crop of the region of interest
2550
+ #
2551
+ # print(bbox)
2552
+ # try:
2553
+ #
2554
+ # plot_n_images_in_line(int24_to_RGB(track_t_minus_1[bbox[0]:bbox[2], bbox[1]:bbox[3]]),
2555
+ # int24_to_RGB(track_t_cur[bbox[0]:bbox[2], bbox[1]:bbox[3]]),
2556
+ # int24_to_RGB(track_t_plus_1[bbox[0]:bbox[2], bbox[1]:bbox[3]]),
2557
+ # matching_neighorhood_score_t_cur_with_t_minus_1[bbox[0]:bbox[2],
2558
+ # bbox[1]:bbox[3]],
2559
+ # matching_neighorhood_score_t_cur_with_t_plus_1[bbox[0]:bbox[2],
2560
+ # bbox[1]:bbox[3]],
2561
+ # title='bug' + str(r_g_b_from_rgb(missing)))
2562
+ # except:
2563
+ # traceback.print_exc()
2564
+ # print('diplay error --> ifnore for naow')
2565
+ #
2566
+ # try:
2567
+ # decision = take_decision(missing, cells_and_their_neighbors_minus_1, cells_and_their_neighbors_cur,
2568
+ # cells_and_their_neighbors_plus_1,
2569
+ # cells_present_in_t_cur_but_absent_in_t_minus_1_score,
2570
+ # cells_present_in_t_cur_but_absent_in_t_plus_1_score,
2571
+ # assume_previous_image_is_GT=True)
2572
+ # except:
2573
+ # traceback.print_exc()
2574
+ # print('pb with decision --> contuinuing but need a fix some day !!!')
2575
+ # continue
2576
+ #
2577
+ # print(missing, ' --> ', decision) # decide whether to keep or discard a cell
2578
+ #
2579
+ # # division
2580
+ # # death
2581
+ # # ignore
2582
+ # # None
2583
+ #
2584
+ # # see unhandled cases
2585
+ #
2586
+ # # cell 4,77,109 is clearly swapped --> can I detect it and fix it in a smart way ?????
2587
+ #
2588
+ # # if decision is None: # --> a lot of these are artifacts --> see how to fix??? or ignore or have mire stringent rules
2589
+ # # if decision is not None and death in decision:
2590
+ # # there is a bug somewhere !!!
2591
+ # # if decision is not None and not ignore in decision:
2592
+ # # if decision is not None and (ignore in decision and (cells_present_in_t_cur_but_absent_in_t_minus_1_score[missing] != 1 or cells_present_in_t_cur_but_absent_in_t_plus_1_score[missing] != 1)): # cells ignore due to sensitivity
2593
+ #
2594
+ # # nb some of the local swap are above 0.5 (maybe it's due to my test sample because I swapped big cells which is unlikely to happen)
2595
+ # #
2596
+ # # shall I start by trying to maximize score for all the cells below or equal 0.5 then do the rest of the code
2597
+ # # most likely swapped cells would have to
2598
+ #
2599
+ # # if score of one is 0 --> probably a far away swap in the track in the current frame --> need fix it
2600
+ # # if first score is 0 --> probably a far away swap in the track in the current frame --> need fix it in current
2601
+ # if decision is None and ((cells_present_in_t_cur_but_absent_in_t_minus_1_score[missing] < 0.5 or
2602
+ # cells_present_in_t_cur_but_absent_in_t_plus_1_score[missing] < 0.5)):
2603
+ # # label_id = np.argwhere(map_tracks_n_label_t_cur[0]==missing)
2604
+ #
2605
+ # print('decision scores', cells_present_in_t_cur_but_absent_in_t_minus_1_score[missing],
2606
+ # cells_present_in_t_cur_but_absent_in_t_plus_1_score[missing])
2607
+ #
2608
+ # label_id = map_tracks_n_label_t_cur[jjj][1]
2609
+ #
2610
+ # # for val in map_tracks_n_label_t_cur[0]:
2611
+ # # if val == missing:
2612
+ # # print('found')
2613
+ # # break
2614
+ # # en effet ça n'y est pas mais pkoi
2615
+ #
2616
+ # # why is cell not found ??
2617
+ # # this is not what it's supposed to be
2618
+ # # try:
2619
+ #
2620
+ # print(missing, '--> ', r_g_b_from_rgb(missing))
2621
+ # print(map_tracks_n_label_t_cur.shape)
2622
+ # # why empty ???? --> should not be so!!!
2623
+ # print(label_id)
2624
+ # # print('track_t_cur==missing',track_t_cur==missing,'track_t_cur==missing')
2625
+ # # check that I have no bug otherwise it will be complex
2626
+ # rps = rps_t_cur[label_id - 1]
2627
+ # bbox = rps.bbox
2628
+ # bbox = [bbox[0] - 50, bbox[1] - 50, bbox[2] + 50, bbox[3] + 50]
2629
+ # # Bounding box ``(min_row, min_col, max_row, max_col)
2630
+ # # do a crop of the region of interest
2631
+ #
2632
+ # print(bbox)
2633
+ # try:
2634
+ #
2635
+ # plot_n_images_in_line(int24_to_RGB(track_t_minus_1[bbox[0]:bbox[2], bbox[1]:bbox[3]]),
2636
+ # int24_to_RGB(track_t_cur[bbox[0]:bbox[2], bbox[1]:bbox[3]]),
2637
+ # int24_to_RGB(track_t_plus_1[bbox[0]:bbox[2], bbox[1]:bbox[3]]),
2638
+ # matching_neighorhood_score_t_cur_with_t_minus_1[bbox[0]:bbox[2],
2639
+ # bbox[1]:bbox[3]],
2640
+ # matching_neighorhood_score_t_cur_with_t_plus_1[bbox[0]:bbox[2],
2641
+ # bbox[1]:bbox[3]], title=str(decision) + ' ' + str(r_g_b_from_rgb(missing)))
2642
+ # except:
2643
+ # traceback.print_exc()
2644
+ # print('diplay error --> ifnore for naow')
2645
+ # # except:
2646
+ # # pass
2647
+ # # TODO get the region of the cell and crop the image so that I can see it
2648
+ # # I could crop the image
2649
+
2650
+ # would be great to see the cells just to see if things are indeed ok and or fix the stuff otherwise
2651
+
2652
+ # show and center on cell
2653
+
2654
+ # start from cells with lowest score and then progressively go up
2655
+ # by default new cells will have the lowest score they are either overseg in current or non segmented cells in previous, if we assume that the first image is good, perfectly corrected then the cell is definitely an overseg in cur
2656
+ # TODO do a brain that takes decision
2657
+ # the brain could also generate various options
2658
+
2659
+ # cells_and_their_neighbors_minus_1 = associate_cells_to_neighbors_ID_in_dict(cells_and_their_neighbors_minus_1)
2660
+ # cells_and_their_neighbors_cur = associate_cells_to_neighbors_ID_in_dict(cells_and_their_neighbors_cur)
2661
+ # cells_and_their_neighbors_plus_1
2662
+
2663
+ # TODO I could try to reidentify swapped cells --> by default they should be close
2664
+ # TO MAP THE CELL I COULD USE THE TRANSLATION BETWEEN THE TWO IMAGES BASED ON ITS NEIGHBOR CELLS TO IDENTIFY IT BACK --> VERY SMART IDEA AND SO EASY TO IMPLEMENT
2665
+ # --> TODO MAYBE CHECK AND DO THIS CODE
2666
+ # AS LONG AS I IMPROVE SCORE I CAN CONTINUE SWAPPING
2667
+ # I NEED CHANGE THE ID IN THE CURRENT CELL AND ALL ITS NEIGHBORS
2668
+ # WHEN I THINK I HAVE IDENTIFIED A SWAPPING I NEED CHECK JUST IN THE NEIGHBORHOOD --> ONE OR TWO ROWS AROUND THE LOST CELL --> VERY GOOD IDEA IN FACT
2669
+
2670
+ # need two mappings --> one on orig and one on tracking --> fairly good idea in fact!!!
2671
+ # je pense que le neighborhood est la solution
2672
+
2673
+ # ça marche pas mal --> ça attire l'attention sur les cellules qui changent de voisin --> marche plutot bien en fait !!!
2674
+ # low score can be due to a division or to a new cell
2675
+ # if cell has low score and is adjacent to a new cell then most likely a division
2676
+ # else this can highlight T1s indeirectly !!!
2677
+
2678
+ # maybe if this is combined to lost cells and smart algo I can reach something really magic
2679
+ # TODO --> do compare all --> TODO --> REALLY FAST !!!
2680
+ # this is really good because it can also identify swapping whereas the other algos cannot --> try combine this to other to differentiate swapping from other features and maybe use this to identify death and divisions
2681
+ # TODO finish that soon
2682
+
2683
+ # when match is poor --> try find best match
2684
+
2685
+ # compute a score for every cell --> shall I reconvert it to a dict to ease the comparison ????
2686
+ # or create
2687
+
2688
+ # plot_n_images_in_line(int24_to_RGB(track_t_minus_1), int24_to_RGB(track_t_cur), int24_to_RGB(track_t_plus_1),
2689
+ # matching_neighorhood_score_t_cur_with_t_minus_1,
2690
+ # matching_neighorhood_score_t_cur_with_t_plus_1)
2691
+
2692
+ # replace this by my multiviewer
2693
+
2694
+
2695
+ # best is to show this as a dialog and get ok or cancel !!
2696
+ # multi_display = ImgDisplayWindow(nb_rows=3, nb_cols=3)
2697
+ # multi_display.set_images(int24_to_RGB(track_t_minus_1), int24_to_RGB(track_t_cur), int24_to_RGB(track_t_plus_1),
2698
+ # matching_neighorhood_score_t_cur_with_t_minus_1,
2699
+ # matching_neighorhood_score_t_cur_with_t_plus_1)
2700
+ # multi_display.show()
2701
+
2702
+ # ok but would be great to have this full screen and fullscreen size
2703
+
2704
+
2705
+ # TODO also show a mask overlay à la TA ??? need a channel sepcified on orig
2706
+ # see how I do that normally ???
2707
+
2708
+
2709
+
2710
+ # print(TA_path_handCorrection_t_minus_1)
2711
+
2712
+ # plt.imshow(apply_lut(matching_neighorhood_score_t_cur_with_t_minus_1,PaletteCreator().create3(PaletteCreator.DNA),convert_to_RGB=True))
2713
+ # plt.show()
2714
+ # do the mask overlap à la TA
2715
+ augment, ok = ImgDisplayWindow.display(draw_mode='pen', nb_rows=3, nb_cols=3, images=[
2716
+ # handCorrection_t_minus_1,
2717
+ # handCorrection_t_cur,
2718
+ # handCorre««««ction_t_plus_1,
2719
+ # createTAmask(original_t_minus_1, handCorrection_t_minus_1),
2720
+ # createTAmask(original_t_cur,handCorrection_t_cur),«
2721
+ # createTAmask( original_t_plus_1,handCorrection_t_plus_1),
2722
+ [original_t_minus_1, handCorrection_t_minus_1],
2723
+ [original_t_cur,handCorrection_t_cur],
2724
+ [original_t_plus_1,handCorrection_t_plus_1],
2725
+ int24_to_RGB(track_t_minus_1), int24_to_RGB(track_t_cur), int24_to_RGB(track_t_plus_1),
2726
+ # apply_lut(matching_neighorhood_score_t_cur_with_t_minus_1,PaletteCreator().create3(PaletteCreator.DNA),convert_to_RGB=True),
2727
+ apply_lut(matching_neighorhood_score_t_cur_with_t_minus_1,matplotlib_to_TA(),convert_to_RGB=True),
2728
+ None,
2729
+ # apply_lut(matching_neighorhood_score_t_cur_with_t_plus_1,PaletteCreator().create3(PaletteCreator.DNA),convert_to_RGB=True)], synced=True)
2730
+ apply_lut(matching_neighorhood_score_t_cur_with_t_plus_1,matplotlib_to_TA(),convert_to_RGB=True)],
2731
+ labels=['image t-1','current image','image t+1',
2732
+ 'track t-1', 'current track', 'track t+1',
2733
+ # 'matching_neighorhood_score_t_cur_with_t_minus_1', None, 'matching_neighorhood_score_t_cur_with_t_plus_1'],
2734
+ 'score t-1/current', None, 'score t+1/current'],
2735
+ # score current image _t_cur_with_t_minus_1
2736
+ synced=True, lst=files, cur_frame_idx=iii)
2737
+
2738
+ # for the first three painters save their mask to the mask of TA --> TODO
2739
+ # PaletteCreator().create3(PaletteCreator.DNA)
2740
+
2741
+ # print('ok0', ok)
2742
+ if not ok:
2743
+ return
2744
+
2745
+ # this is to autosave the edited masks maybe some day also support track connection or swapping --> TODO
2746
+ mask_save = [TA_path_handCorrection_t_minus_1, TA_path_handCorrection_t_cur, TA_path_handCorrection_t_plus_1]
2747
+ for i in range(3):
2748
+ mask = augment[i].get_mask()
2749
+ if mask is not None:
2750
+ Img(mask, dimensions='hw').save(mask_save[i])
2751
+
2752
+
2753
+ # it
2754
+
2755
+
2756
+ # when the user is done --> just save the modified masks
2757
+ # need get painters out or all masks out
2758
+ # and save them
2759
+
2760
+
2761
+ # in some case it can be useful to check even more frames
2762
+ # for example
2763
+
2764
+ # this can also be done using label and regionprops --> see what is the best choice for this
2765
+ # in a way I could get properties only of the interesting cells
2766
+ # check the intersections I need
2767
+
2768
+ # overseg is smthg that is present on the middle frame and not on the one before and after
2769
+ # an underseg is something that is absent from middle image and present in the two others # pb is that since tracks don't match I will not necessarily detect it but I may be able to detect it based on neighborhood but the algo need be super smart --> see if I can find a way to do that !!!
2770
+
2771
+ # underseg could be smthg present in the two fisrt and not in the last --> but some apoptotic cells would be misidentified --> also these errors most likely require human intervention
2772
+ # could do a code that follows the error and lets the user decide what TODO
2773
+ # check also swappings and see if I can fix them!!!!
2774
+
2775
+ # I could pass underseg to the next
2776
+ # can I identify a cell based on its neighbors --> most likely yes and if so I should be able to fix most errors --> provided there are little errors
2777
+
2778
+ # print missing between consecutive frames
2779
+ # missing_between_t_cur_and_t_minus_1 = np.setdiff1d(track_t_cur, track_t_minus_1) # potentially underseg
2780
+ # missing_between_t_cur_and_t_plus_1 = np.setdiff1d(track_t_cur, track_t_plus_1) # potentially overeseg
2781
+ #
2782
+ # # these are true overseg
2783
+ # overseg_t_cur = np.intersect1d(missing_between_t_cur_and_t_minus_1,
2784
+ # missing_between_t_cur_and_t_plus_1)
2785
+
2786
+ # can I also get infos from partial intersections between two consecutive frames --> most likely yes
2787
+ # for example if a cell is newly appearing in last and absent in the middle and if its neigbors match that in the first then there is likely to be an underseg that need be fixed !!!
2788
+ # check and reimplement my swapping algo to see how I can deal with that
2789
+
2790
+ # do checks only if things are missing or if some pbs are encountered --> if so --> then fix them!!!
2791
+
2792
+ # NB IN FACT AN OVERSEG IN CUR CAN BE DUE TO AN UNDERSEG IN PREVIOUS --> KEEP IN MIND AND TRY TO DESIGN SOME SUPRA INTELLIGENT CODE TO FIX THAT!!!
2793
+
2794
+ # ça a l'air de marcher mais faut vraiment que le tracking soit perfect --> see how
2795
+ # maybe I can do an hybrid correction where the soft detects the error but the user is asked to fix it or to chose between automated solutions --> TODO !!!
2796
+ # print('overseg_t_cur', overseg_t_cur)
2797
+ # # qd meme ça marche pas mal!!!!
2798
+ #
2799
+ # # TODO try show the overseg cells or save them so that I can check by myself
2800
+ # # do a plotter that plots 3 images + the ovgerseg cells
2801
+ #
2802
+ # # in fact I may have smarter rules --> for example if something is present in two consecutive images it is likely to be present in the previous one too!!!
2803
+ # # see the best way TODO that
2804
+ # # TODO also identify swappings
2805
+ #
2806
+ # overseg_mask = np.zeros_like(track_t_cur)
2807
+ # overseg_mask[track_t_cur == 0xFFFFFF] = 64
2808
+ #
2809
+ # for missing in overseg_t_cur:
2810
+ # overseg_mask[track_t_cur == missing] = 255
2811
+ #
2812
+ # for missing in missing_between_t_cur_and_t_minus_1:
2813
+ # overseg_mask[track_t_cur == missing] = 128
2814
+ #
2815
+ # for missing in missing_between_t_cur_and_t_minus_1:
2816
+ # overseg_mask[
2817
+ # track_t_cur == missing] = 192 # practically these are all the same cells as in overseg_t_cur --> DO I HAVE A BUG ????
2818
+ #
2819
+ # # ça parait realiste mais checker usr un vrai example avec 3 images
2820
+ #
2821
+ # # plt.imshow(overseg_mask)
2822
+ # # plt.show()
2823
+ # plot_n_images_in_line(int24_to_RGB(track_t_minus_1), int24_to_RGB(track_t_cur), int24_to_RGB(track_t_plus_1),
2824
+ # overseg_mask)
2825
+ #
2826
+ # underseg_mask = np.zeros_like(track_t_cur)
2827
+ #
2828
+ # # print missing between consecutive frames
2829
+ #
2830
+ # # nb also don't forget that the intersections can be done both ways and that some info is stored in there too !!! --> TODO do fix all!!!
2831
+ # lost_cells_between_t_minus_1_and_current = np.setdiff1d(track_t_minus_1, track_t_cur) # potentially underseg
2832
+ # lost_cells_between_t_plus_1_and_current = np.setdiff1d(track_t_plus_1, track_t_cur) # potentially overeseg
2833
+ #
2834
+ # for missing in lost_cells_between_t_minus_1_and_current:
2835
+ # underseg_mask[track_t_minus_1 == missing] = 255
2836
+ #
2837
+ # for missing in lost_cells_between_t_plus_1_and_current:
2838
+ # underseg_mask[track_t_plus_1 == missing] = 128
2839
+ #
2840
+ # underseg_mask[track_t_cur == 0xFFFFFF] = 64
2841
+ #
2842
+ # # there is indeed important infos in that too
2843
+ # # if cells do really match well --> then I could check them for sure
2844
+ #
2845
+ # # shall I try a resegmentation !!!
2846
+ #
2847
+ # # TODO maybe take a simpler example than in the ovipo because it's too complex
2848
+ #
2849
+ # # ça parait realiste mais checker usr un vrai example avec 3 images
2850
+ #
2851
+ # # plt.imshow(overseg_mask)
2852
+ # # plt.show()
2853
+ # plot_n_images_in_line(int24_to_RGB(track_t_minus_1), int24_to_RGB(track_t_cur), int24_to_RGB(track_t_plus_1),
2854
+ # underseg_mask)
2855
+ #
2856
+ # # these are true overseg
2857
+ # # overseg_t_cur = np.intersect1d(missing_between_t_cur_and_t_minus_1,
2858
+ # # missing_between_t_cur_and_t_plus_1)
2859
+ #
2860
+ # # should I care about the common cells --> yes maybe if they do not share the same neighbors --> in that case this most likely means they are swapped -->
2861
+ #
2862
+ # # then I could fix them
2863
+ # # in fact I could detect neighborhood only for the common cells to see if ok
2864
+ # #
2865
+ #
2866
+ # #
2867
+ # #
2868
+ # # print(overseg_t_cur)
2869
+ # #
2870
+ # # common_cells = np.intersect1d(cells_in_current, cells_in_prev)
2871
+ # # print(common_cells)
2872
+ # # # print("Unique values in array1 that are not in array2:")
2873
+ # # lost_cells =np.setdiff1d(cells_in_current, cells_in_prev)
2874
+ # # print(lost_cells)
2875
+ #
2876
+ # # that is ok all of this is super fast --> now try to do it for real and for the magic of it
2877
+ #
2878
+ # # maybe also store seg/labels so that I don't need redo them
2879
+ # # for all diverging cells I could check them and do all sorts to stuff with them
2880
+ #
2881
+ # # can I correct for swapping too
2882
+ #
2883
+ # # not bad --> I could then see if the cell comes back or vanishes
2884
+ # # I could maybe compare neighbours TODO magics
2885
+ #
2886
+ # # TODO --> see what I can do with that !!!
2887
+ #
2888
+ # # lost cells and new cells
2889
+ #
2890
+ # # pas mal en fait
2891
+ #
2892
+ # # avec ça je dois avoir à peu pres tout ce que je veux
2893
+ #
2894
+ # # maybe get bonds coords too using coords rather than images --> in a way that is a good idea
2895
+ #
2896
+ # # TODO maybe also associate bonds to cells --> can eb useful and not that hard to do --> then I have evrything to do my desired code
2897
+ #
2898
+ # #
2899
+ #
2900
+ # # not bad in fact generate all the things I need and just get the desired output
2901
+ #
2902
+ # # really not bad !!!
2903
+ #
2904
+ # # ou bien associer les neighbors à une cellule
2905
+ #
2906
+ # # loop pour chaque cellule
2907
+ #
2908
+ # # nb one can call a numba function this way --> very easy in fact
2909
+ # # sum_array_numba = jit()(sum_array)
2910
+ #
2911
+ # # plt.imshow(vertices)
2912
+ # # plt.show()
2913
+ # # bonds = find_bonds(img) # chaque passage double le temps --> a faire que si necessaire donc
2914
+ # # plt.imshow(bonds)
2915
+ # # plt.show()
2916
+ #
2917
+ # # we do have our three files --> generate something useful out of them
2918
+ # #
2919
+ # # for file_to_read in files_to_read:
2920
+ # # try:
2921
+ # # tracked_cells_resized, TA_path = smart_name_parser(file_to_read, ordered_output=['TA', 'tracked_cells_resized.png'])
2922
+ # # except:
2923
+ # # tracked_cells_resized = TA_path = None
2924
+ # # print(tracked_cells_resized, TA_path)
2925
+
2926
+ # print('files are useful', files_to_read)
2927
+
2928
+ # hack my viewer code to synchronize everything
2929
+ # get the code back from the stuff of Amrutha and even further finish it --> would also be a nice free floating window!!!
2930
+ # now try the synchronous multiview of images --> should not be that hard and do the multi view
2931
+ # then compute the changes and correction using multiview stuff --> write a set of rules and see if that works and if things are missed then offer corrections --> TODO
2932
+ # TODO --> do all
2933
+ if __name__ == '__main__':
2934
+ start = timer()
2935
+
2936
+ if True:
2937
+ # img_t_minus1 = RGB_to_int24(
2938
+ # Img('/E/Sample_images/tracking_test/test_uncropped/200319.lif_t021/tracked_cells_resized.tif'))
2939
+ # img_t_cur = RGB_to_int24(
2940
+ # Img('/E/Sample_images/tracking_test/test_uncropped/200319.lif_t022/tracked_cells_resized.tif'))
2941
+ img_t_minus1 = RGB_to_int24(
2942
+ Img('/E/Sample_images/sample_images_PA/mini10_fake_swaps/focused_Series012/tracked_cells_resized.tif'))
2943
+ img_t_cur = RGB_to_int24(
2944
+ Img('/E/Sample_images/sample_images_PA/mini10_fake_swaps/focused_Series014/tracked_cells_resized.tif'))
2945
+ divs = detect_divisions(img_t_cur, img_t_minus1)
2946
+ print(divs)
2947
+
2948
+ # very cool set of tools by the way!!!
2949
+ border_cells = get_border_cells(img_t_cur)
2950
+ border_cells_plus_one = get_border_cells_plus_one(get_cells_and_their_neighbors_from_image(img_t_cur), border_cells, remove_border_cells=True)# pb is that it includes border cells --> is now an option
2951
+
2952
+ border_cells = plot_anything_a_la_TA(img_t_cur, border_cells, color=0xFF0000)
2953
+ border_cells_plus_one = plot_anything_a_la_TA(img_t_cur, border_cells_plus_one, color=0xFFFF00)
2954
+
2955
+ divisions = plot_dividing_cells_a_la_TA(img_t_cur, divs, plot_cell_outline=False) # less stringent parameters to really see all the divisions --> exclude_cells_with_size_difference_superior=12, remove_divisions_involving_a_border_cell=False)
2956
+
2957
+ plt.imshow(divisions)
2958
+ plt.show()
2959
+
2960
+ plot_n_images_in_line(int24_to_RGB(img_t_minus1),int24_to_RGB(img_t_cur), divisions, int24_to_RGB(border_cells), int24_to_RGB(border_cells_plus_one))
2961
+ # plt.imshow(divisions)
2962
+ # plt.show()
2963
+
2964
+ import sys
2965
+
2966
+ sys.exit(0)
2967
+
2968
+ if False:
2969
+ # NB THERE IS SOMETHING VERY INTERESTING IN THIS OVERLAP METHOD AND IN ADDITION IT IS VERY FAST --> REALLY CAN BE USEFUL MAYBE ALSO TO RESTRICT TO SOMETHING REALISTIC THE CELLS
2970
+
2971
+ # what if I do an and between the two images --> I can see if its color is fitting --> if not could try to find a better match --> maybe a good idea
2972
+
2973
+ # and_img = np.logical_and(RGB_to_int24(Img('/E/Sample_images/tracking_test/test_uncropped/200319.lif_t021/tracked_cells_resized.tif')), RGB_to_int24(Img('/E/Sample_images/tracking_test/test_uncropped/200319.lif_t022/tracked_cells_resized.tif')))
2974
+ # and_img = np.logical_and(RGB_to_int24(Img('/E/Sample_images/tracking_test/test_uncropped/200319.lif_t021/tracked_cells_resized.tif')), RGB_to_int24(Img('/E/Sample_images/tracking_test/test_uncropped/200319.lif_t022/tracked_cells_resized.tif')))
2975
+ img_t_minus1 = RGB_to_int24(
2976
+ Img('/E/Sample_images/tracking_test/test_uncropped/200319.lif_t021/tracked_cells_resized.tif'))
2977
+ img_t_cur = RGB_to_int24(
2978
+ Img('/E/Sample_images/tracking_test/test_uncropped/200319.lif_t022/tracked_cells_resized.tif'))
2979
+
2980
+ # find_best_matches_both_ways(img_t_cur, img_t_another)
2981
+
2982
+ and_img = np.copy(img_t_cur)
2983
+ and_img[img_t_cur != img_t_minus1] = 0
2984
+ # and_img[img_t_cur==img_t_minus1]=img_t_minus1[img_t_cur==img_t_minus1]
2985
+ plt.imshow(int24_to_RGB(and_img))
2986
+ plt.show()
2987
+
2988
+ # matching
2989
+
2990
+ # maybe I could use this trick to get the translation
2991
+ xor_img = np.zeros_like(img_t_cur) # np.copy(img_t_cur)
2992
+ # xor_img[img_t_cur==img_t_minus1]=0
2993
+ xor_img[img_t_cur != img_t_minus1] = img_t_minus1[img_t_cur != img_t_minus1]
2994
+
2995
+ # img_t_cur[xor_img!=0]=xor_img[xor_img!=0]
2996
+
2997
+ plt.imshow(int24_to_RGB(xor_img))
2998
+ plt.show()
2999
+
3000
+ # maybe use that to find the most frequent value !!!!
3001
+ # counts = np.bincount(a)
3002
+ # print(np.argmax(counts))
3003
+
3004
+ # print(xor_img==0)
3005
+
3006
+ # merge = np.copy(xor_img)
3007
+ # # merge[and_img+xor_img)!=0]=and_img[(and_img+xor_img)!=0]
3008
+ # # merge[xor_img!=0]=xor_img[xor_img!=0]
3009
+ # # merge[xor_img!=0]=xor_img[(and_img+xor_img)!=0]
3010
+ # merge[xor_img==0]=and_img[xor_img==0]
3011
+ # plt.imshow(int24_to_RGB(merge))
3012
+ # plt.show()
3013
+ # if I combine both images I should get the most likely id for every cell
3014
+
3015
+ Img(int24_to_RGB(xor_img), dimensions='hwc').save('/E/Sample_images/Consensus_learning/gray/xor_img.tif',
3016
+ mode='raw')
3017
+
3018
+ Img(int24_to_RGB(and_img), dimensions='hwc').save('/E/Sample_images/Consensus_learning/gray/and_img.tif',
3019
+ mode='raw')
3020
+ Img(int24_to_RGB(img_t_cur), dimensions='hwc').save('/E/Sample_images/Consensus_learning/gray/img_t_cur.tif',
3021
+ mode='raw')
3022
+ Img(int24_to_RGB(img_t_minus1), dimensions='hwc').save(
3023
+ '/E/Sample_images/Consensus_learning/gray/img_t_minus1.tif', mode='raw')
3024
+
3025
+ xor_img = xor_img & and_img
3026
+
3027
+ print(xor_img.shape)
3028
+ # xor_img[xor_img==0]=and_img[xor_img==0]
3029
+ Img(int24_to_RGB(xor_img), dimensions='hwc').save('/E/Sample_images/Consensus_learning/gray/comb.tif',
3030
+ mode='raw')
3031
+ # la somme redonne l'image t-1 --> why not t0
3032
+
3033
+ # if a cell is almost full black
3034
+ # I can do xor to find non matching color
3035
+ # that is an easy and fast trick to find possible match for a cell or when cells do not match -->
3036
+
3037
+ print('total time',
3038
+ timer() - start)
3039
+
3040
+ # --> seven secs
3041
+ import sys
3042
+
3043
+ sys.exit(0)
3044
+
3045
+ if False:
3046
+
3047
+ # --> ok c'est ce truc que je dois hacker
3048
+
3049
+ # files = loadlist('/E/Sample_images/sample_images_denoise_manue/210312_armGFP_line2_suz_39h30APF/predict/predict_model_nb_0/list.lst')
3050
+ # files = loadlist('/E/Sample_images/sample_images_PA/mini10/liste.lst')
3051
+ files = loadlist(
3052
+ '/E/Sample_images/sample_images_PA/mini10_fake_swaps/liste.lst') # fake manually added swaped cells
3053
+ # files = loadlist('/E/Sample_images/tracking_test/old') # very good for testing cause a lot of errors and a few moderate swap # maybe too many errors to start with
3054
+ print(files)
3055
+
3056
+ # TODO try restrict in clone only
3057
+
3058
+ # /usr/local/bin/python3.7 /home/aigouy/mon_prog/Python/epyseg_pkg/personal/pyTA/tracking/tracking_error_detector_and_fixer.py
3059
+ # ['/E/Sample_images/sample_images_PA/mini/focused_Series012.png', '/E/Sample_images/sample_images_PA/mini/focused_Series014.png', '/E/Sample_images/sample_images_PA/mini/focused_Series015.png', '/E/Sample_images/sample_images_PA/mini/focused_Series016.png', '/E/Sample_images/sample_images_PA/mini/focused_Series018.png', '/E/Sample_images/sample_images_PA/mini/focused_Series019.png']
3060
+ # [('/E/Sample_images/sample_images_PA/mini/focused_Series014.png', '/E/Sample_images/sample_images_PA/mini/focused_Series014'), ('/E/Sample_images/sample_images_PA/mini/focused_Series014.png', '/E/Sample_images/sample_images_PA/mini/focused_Series014')]
3061
+ #
3062
+ # Process finished with exit code 0
3063
+
3064
+ track_cells(files)
3065
+
3066
+ if True:
3067
+
3068
+ # ça marche super --> appliquer ça à l'ovipo !!! --> TODO
3069
+ import sys
3070
+ app = QApplication(sys.argv)
3071
+ # --> ok c'est ce truc que je dois hacker
3072
+
3073
+ # files = loadlist('/E/Sample_images/sample_images_denoise_manue/210312_armGFP_line2_suz_39h30APF/predict/predict_model_nb_0/list.lst')
3074
+ # files = loadlist('/E/Sample_images/sample_images_PA/mini10/liste.lst')
3075
+ files = loadlist(
3076
+ '/E/Sample_images/sample_images_PA/mini10_fake_swaps/liste.lst') # fake manually added swaped cells
3077
+ # files = loadlist('/E/Sample_images/tracking_test/old') # very good for testing cause a lot of errors and a few moderate swap # maybe too many errors to start with
3078
+ print(files)
3079
+
3080
+ # TODO try restrict in clone only
3081
+
3082
+ # /usr/local/bin/python3.7 /home/aigouy/mon_prog/Python/epyseg_pkg/personal/pyTA/tracking/tracking_error_detector_and_fixer.py
3083
+ # ['/E/Sample_images/sample_images_PA/mini/focused_Series012.png', '/E/Sample_images/sample_images_PA/mini/focused_Series014.png', '/E/Sample_images/sample_images_PA/mini/focused_Series015.png', '/E/Sample_images/sample_images_PA/mini/focused_Series016.png', '/E/Sample_images/sample_images_PA/mini/focused_Series018.png', '/E/Sample_images/sample_images_PA/mini/focused_Series019.png']
3084
+ # [('/E/Sample_images/sample_images_PA/mini/focused_Series014.png', '/E/Sample_images/sample_images_PA/mini/focused_Series014'), ('/E/Sample_images/sample_images_PA/mini/focused_Series014.png', '/E/Sample_images/sample_images_PA/mini/focused_Series014')]
3085
+ #
3086
+ # Process finished with exit code 0
3087
+
3088
+ # TODO need handle tracking and need break buttons to stop the loop
3089
+ help_user_correct_errors(files)
3090
+ print('total time',
3091
+ timer() - start) # --> total time 4.510682744003134 in numba vs 740 secs (forever) otherwise !!! --> too bad I didn't find this earlier --> that would have increased the speed of my code so much
3092
+
3093
+ # sys.exit(app.exec_())
3094
+ sys.exit(0)
3095
+
3096
+
3097
+
3098
+ print('total time',
3099
+ timer() - start) # --> total time 4.510682744003134 in numba vs 740 secs (forever) otherwise !!! --> too bad I didn't find this earlier --> that would have increased the speed of my code so much