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,314 @@
1
+ # seems ok and better working again
2
+ import random
3
+ from scipy import ndimage as ndi
4
+ import numpy as np
5
+ import matplotlib.pyplot as plt
6
+ from batoolset.img import Img
7
+ from skimage import measure
8
+ from skimage.util import invert, img_as_ubyte
9
+ from skimage import filters
10
+ from skimage.segmentation import watershed
11
+ from skimage.util import invert
12
+ from timeit import default_timer as timer
13
+ from batoolset.tools.logger import TA_logger # logging
14
+ from numba import jit, njit
15
+ from scipy.ndimage import generic_filter
16
+
17
+ logger = TA_logger()
18
+
19
+ __DEBUG__ = False
20
+
21
+ def wshed(img, channel=None, weak_blur=None, strong_blur=None, seeds='mask', min_seed_area=None, is_white_bg=False, fix_scipy_wshed=False, force_dual_pass=False):
22
+ """
23
+ Perform watershed segmentation on an image.
24
+
25
+ Args:
26
+ img (numpy.ndarray): The input image.
27
+ channel (int): The channel index to be used from the image (optional).
28
+ weak_blur (float): The sigma value for weak blurring (optional).
29
+ strong_blur (float): The sigma value for strong blurring (optional).
30
+ seeds (str, list, or numpy.ndarray): The seeds for watershed segmentation. Can be 'mask', a list of 2D coordinates, or a labeled image (optional).
31
+ min_seed_area (int): The minimum seed area for dual-pass watershed (optional).
32
+ is_white_bg (bool): Whether the image has a white background (optional).
33
+ fix_scipy_wshed (bool): Whether to fix missing watershed lines in scipy (optional).
34
+ force_dual_pass (bool): Force dual-pass watershed even if min_seed_area is not specified (optional).
35
+
36
+ Returns:
37
+ numpy.ndarray: The segmented image.
38
+
39
+ """
40
+ if __DEBUG__:
41
+ start = timer()
42
+
43
+ if min_seed_area is None and force_dual_pass:
44
+ min_seed_area = 0
45
+
46
+ if weak_blur is None and strong_blur is not None:
47
+ weak_blur = strong_blur
48
+ strong_blur = None
49
+
50
+ if strong_blur is not None or weak_blur is not None:
51
+ if isinstance(seeds, str):
52
+ seeds = None
53
+
54
+ if channel:
55
+ if len(img.shape) > 2:
56
+ img = img[..., channel]
57
+
58
+ if is_white_bg:
59
+ img = invert(img)
60
+
61
+ strong = None
62
+ if weak_blur:
63
+ weak = filters.gaussian(img, sigma=weak_blur, preserve_range=True, mode='wrap')
64
+ else:
65
+ weak = img
66
+ if strong_blur:
67
+ strong = filters.gaussian(img, sigma=strong_blur, preserve_range=True, mode='wrap')
68
+
69
+ if __DEBUG__:
70
+ print('blur ' + str(timer() - start) + ' s')
71
+
72
+ if isinstance(seeds, str) and seeds == 'mask':
73
+ markers = measure.label(weak, connectivity=1, background=255)
74
+ elif isinstance(seeds, list):
75
+ marker = np.zeros_like(weak, dtype=np.int32)
76
+ seeds = np.asarray(seeds)
77
+ marker[seeds[:, 0], seeds[:, 1]] = 1
78
+ markers = measure.label(marker, connectivity=1, background=0)
79
+ elif isinstance(seeds, np.ndarray):
80
+ if seeds.shape == weak.shape:
81
+ markers = seeds
82
+ else:
83
+ marker = np.zeros_like(weak, dtype=np.int32)
84
+ marker[seeds[:, 0], seeds[:, 1]] = 1
85
+ markers = measure.label(marker, connectivity=1, background=0)
86
+ else:
87
+ if is_white_bg:
88
+ if strong_blur:
89
+ local_maxi = ndi.maximum_filter(strong, size=3) == strong
90
+ del strong
91
+ else:
92
+ local_maxi = ndi.maximum_filter(weak, size=3) == weak
93
+ else:
94
+ if strong_blur:
95
+ local_maxi = ndi.minimum_filter(strong, size=3) == strong
96
+ del strong
97
+ else:
98
+ local_maxi = ndi.minimum_filter(weak, size=3) == weak
99
+ markers = measure.label(local_maxi)
100
+ if __DEBUG__:
101
+ print('local max ' + str(timer() - start) + ' s')
102
+
103
+ labels_ws = watershed(weak, markers=markers, watershed_line=True)
104
+ del weak
105
+ del markers
106
+
107
+ if fix_scipy_wshed:
108
+ labels_ws = full_numba_wshed_fixer(labels_ws)
109
+
110
+ tmp = np.zeros_like(labels_ws)
111
+ tmp[labels_ws == 0] = 255
112
+ labels_ws = tmp
113
+ del tmp
114
+
115
+ if __DEBUG__:
116
+ print('wshed 1 ' + str(timer() - start) + ' s')
117
+
118
+ if (min_seed_area is not None and min_seed_area > 0) or force_dual_pass:
119
+ wshed_mask = np.copy(labels_ws)
120
+ del labels_ws
121
+ label = measure.label(wshed_mask, connectivity=1, background=255)
122
+ most_frequent_segmentation_mask, count = np.unique(label, return_counts=True)
123
+ cells_to_remove = most_frequent_segmentation_mask[count <= min_seed_area]
124
+
125
+ if cells_to_remove.size == 0 and not force_dual_pass:
126
+ final_mask = wshed_mask
127
+ del label
128
+ else:
129
+ for cell in cells_to_remove:
130
+ wshed_mask[label == cell] = 255
131
+ del label
132
+
133
+ wshed_mask = watershed(wshed_mask, markers=None, watershed_line=True)
134
+ final_mask = np.zeros_like(wshed_mask)
135
+ final_mask[wshed_mask == 0] = 255
136
+ del wshed_mask
137
+ else:
138
+ final_mask = labels_ws
139
+
140
+ if final_mask.max() == final_mask.min():
141
+ final_mask = np.zeros_like(final_mask, dtype=np.uint8)
142
+ else:
143
+ final_mask = final_mask.astype(np.uint8)
144
+
145
+ if __DEBUG__:
146
+ print('final wshed ' + str(timer() - start) + ' s')
147
+
148
+ return final_mask
149
+
150
+ @njit
151
+ def full_numba_wshed_fixer(img):
152
+ height = img.shape[0]
153
+ width = img.shape[1]
154
+ for jjj in range(height):
155
+ last_pixel = -1
156
+ for iii in range(width):
157
+ pixel = img[jjj, iii]
158
+ if pixel == 0:
159
+ last_pixel = -1
160
+ continue
161
+ if last_pixel == -1:
162
+ last_pixel = pixel
163
+ else:
164
+ if pixel == 0:
165
+ last_pixel = -1
166
+ elif last_pixel != pixel and pixel != 0:
167
+ img[jjj, iii] = 0
168
+ last_pixel = pixel
169
+
170
+ for iii in range(width):
171
+ last_pixel = -1
172
+ for jjj in range(height):
173
+ pixel = img[jjj, iii]
174
+ if pixel == 0:
175
+ last_pixel = -1
176
+ continue
177
+ if last_pixel == -1:
178
+ last_pixel = pixel
179
+ else:
180
+ if pixel == 0:
181
+ last_pixel = -1
182
+ elif last_pixel != pixel and pixel != 0:
183
+ img[jjj, iii] = 0
184
+ last_pixel = pixel
185
+
186
+ return img
187
+
188
+ @njit
189
+ def detect_wshed_line(P):
190
+ if P[4] == 0:
191
+ return 0
192
+ corrected_ids = set(P)
193
+ size = len(corrected_ids)
194
+ if size == 3:
195
+ if np.count_nonzero(P) == 7:
196
+ if P[1] == 0 and P[7] == 0:
197
+ return 255
198
+ if P[3] == 0 and P[5] == 0:
199
+ return 255
200
+ if P[0] == 0 and P[8] == 0:
201
+ return 255
202
+ if P[2] == 0 and P[6] == 0:
203
+ return 255
204
+ return 0
205
+
206
+ if __name__ == '__main__':
207
+
208
+ # all works now try to run the local wshed on the image
209
+ # --> need a small test stuff
210
+ # test apply ctrl + M to the image --> see how I can do that properly
211
+
212
+ if True:
213
+ # 7.7357873320002 seconds --> passe à 19 secs avec le fix du wshed --> probably not worth it but put it as an option
214
+ # testing seeds are already a label in the proper shape of the image
215
+ img = Img('/E/Sample_images/sample_images_PA/test_complete_wing_raphael/neo_mask.tif')
216
+ # test seeded wshed
217
+ start = timer()
218
+ seeds = np.zeros_like(img)
219
+
220
+ # out = watershed(img, seeds=[[10,20],[60,20]])
221
+ # out = watershed(img, seeds=[[0,0],[800,1900]])
222
+ # out = watershed(img, seeds=[[780,1800],[800,1900]])
223
+ for i in range(1, 3000):
224
+ seeds[random.randint(0, img.shape[0] - 1), random.randint(0, img.shape[1] - 1)] = i
225
+
226
+ # print(tuple(seeds))
227
+ # print(seeds[:, 0])
228
+
229
+ # out = wshed(img, weak_blur=1,seeds=seeds)
230
+ # out = wshed(img, seeds=seeds) # --> 7.7357873320002 seconds
231
+ # out = wshed(img, seeds=seeds, fix_scipy_wshed=True) # --> 19 secs
232
+ out = wshed(img, seeds=seeds, fix_scipy_wshed=True) # --> new algo full numba --> 15secs --> not that bad... just double the time
233
+
234
+ # not so bad --> all is ok now
235
+ # check what seeds I can make # maybe do local stuff too --> would need a bounding box then !!!
236
+
237
+ print('total time', timer() - start)
238
+ plt.imshow(out)
239
+ plt.show()
240
+
241
+ if False:
242
+ # testing new kinds of seeds --> just for a test
243
+ img = Img('/E/Sample_images/sample_images_PA/test_complete_wing_raphael/neo_mask.tif')
244
+ # test seeded wshed
245
+ start = timer()
246
+
247
+ # out = watershed(img, seeds=[[10,20],[60,20]])
248
+ # out = watershed(img, seeds=[[0,0],[800,1900]])
249
+ # out = watershed(img, seeds=[[780,1800],[800,1900]])
250
+ seeds = []
251
+ for i in range(2000):
252
+ seeds.append([random.randint(0, img.shape[0] - 1), random.randint(0, img.shape[1] - 1)])
253
+
254
+ if random.random() > 0.5:
255
+ # print(seeds)
256
+ seeds = np.asarray(seeds) # 2D seeds
257
+
258
+ # print(tuple(seeds))
259
+
260
+ # print(seeds[:, 0])
261
+
262
+ out = wshed(img, seeds=seeds)
263
+
264
+ # check what seeds I can make # maybe do local stuff too --> would need a bounding box then !!!
265
+
266
+ print('total time', timer() - start)
267
+ plt.imshow(out)
268
+ plt.show()
269
+
270
+ if False:
271
+ # ça marche ça c'est vraiment la correction de TA et c'est pas trop slow --> ok
272
+ # le removing of seeds est slow --> if I could make it faster would be cool but ok
273
+ img = Img('/E/Sample_images/sample_images_PA/test_complete_wing_raphael/neo_mask.tif')
274
+ # test seeded wshed
275
+ start = timer()
276
+ out = wshed(img, min_seed_area=0, seeds='mask') # self instead of seeds
277
+
278
+ # check what seeds I can make # maybe do local stuff too --> would need a bounding box then !!!
279
+
280
+ print('total time', timer() - start)
281
+ plt.imshow(out)
282
+ plt.show()
283
+
284
+ # do i need seeds
285
+ if False:
286
+ # ça marche ça c'est vraiment la correction de TA et c'est pas trop slow --> ok
287
+ # le removing of seeds est slow --> if I could make it faster would be cool but ok
288
+ img = Img('/E/Sample_images/sample_images_PA/test_complete_wing_raphael/neo_mask.tif')
289
+ # test seeded wshed
290
+ start = timer()
291
+ out = wshed(img, min_seed_area=3, seeds='mask') # self instead of seeds
292
+ print('total time', timer() - start)
293
+ plt.imshow(out)
294
+ plt.show()
295
+ # test default wshed
296
+ if False:
297
+ # img = Img('/E/Sample_images/sample_images_PA/mini/focused_Series012.png')[...,1]
298
+ # img = Img('/E/Sample_images/sample_images_PA/mini/focused_Series012.png')
299
+ img = Img('/E/Sample_images/sample_images_PA/test_complete_wing_raphael/Optimized_projection_018.png')[
300
+ ..., 1] # 27.9 secs --> maybe not so bad secs per image --> slow
301
+ start = timer()
302
+ # nb first and second blur are inverted --> rather use weak and strong blur --> TODO
303
+ # fix also the minimal size stuff , can also use np.unique to speed up things
304
+ out = wshed(img, weak_blur=1, strong_blur=5, min_seed_area=3, is_white_bg=False)
305
+ Img(out).save('/E/Sample_images/sample_images_PA/test_complete_wing_raphael/neo_mask.tif')
306
+
307
+ # if only one blur then must set weak blur
308
+ # out = watershed(img, weak_blur=5, min_seed_area=3, is_white_bg=False) # --> 3 secs # --> sans filtering --> gain de 7 secs
309
+
310
+ # TODO try to play with seeds to support all sorts of interesting stuff such as manual seeds
311
+
312
+ print('total time', timer() - start)
313
+ plt.imshow(out)
314
+ plt.show()
File without changes
@@ -0,0 +1,329 @@
1
+ import traceback
2
+ import matplotlib.pyplot as plt
3
+
4
+ from batoolset.ta.measurements.measurements3D.get_point_on_surface_if_centroid_is_bad import point_on_surface
5
+ from batoolset.ta.utils.TA_tools import get_TA_clone_file_name
6
+ from batoolset.img import RGB_to_int24, Img
7
+ from batoolset.files.tools import smart_name_parser
8
+ from skimage.measure import label, regionprops
9
+ import numpy as np
10
+ from batoolset.tools.early_stopper_class import early_stop
11
+ from batoolset.tools.logger import TA_logger # logging
12
+
13
+ logger = TA_logger()
14
+
15
+ # deprecated --> use another code if possible
16
+ def convert_db_xy_coordiantes_to_local_cell_ID_for_clones(db_path, table_name, image_for_correspondance_label_or_RGB24, return_image=False):
17
+ """
18
+ Converts database coordinates to local cell IDs for clones.
19
+
20
+ Args:
21
+ db_path (str): The path to the database.
22
+ table_name (str): The name of the table containing the coordinates.
23
+ image_for_correspondance_label_or_RGB24 (ndarray): The image used for correspondence between labels and RGB24 values.
24
+ return_image (bool, optional): A flag indicating whether to return an image or a set of cells.
25
+ Defaults to False.
26
+
27
+ Returns:
28
+ list or ndarray: The output, either a list of cells or an image.
29
+
30
+ """
31
+ from batoolset.ta.database.sql import TAsql
32
+ import numpy as np
33
+
34
+ output = [] # Initialize the output variable
35
+ db = None
36
+ try:
37
+ db = TAsql(db_path) # Open the database connection
38
+
39
+ # Get the coordinates from the database
40
+ query_results = db.run_SQL_command_and_get_results('SELECT * FROM ' + table_name, return_header=False)
41
+
42
+ if return_image:
43
+ output = np.zeros_like(image_for_correspondance_label_or_RGB24) # Create an empty image
44
+
45
+ for coords in query_results:
46
+ color = image_for_correspondance_label_or_RGB24[coords[0], coords[1]] # Get the color value at the coordinates
47
+
48
+ if return_image:
49
+ output[image_for_correspondance_label_or_RGB24 == color] = color # Assign the color to corresponding pixels in the image
50
+ else:
51
+ output.append(color) # Append the color to the list of cells
52
+ except:
53
+ import traceback
54
+ traceback.print_exc()
55
+ logger.error('Something went wrong, selection could not be converted to 2D coordinates')
56
+ finally:
57
+ if db is not None:
58
+ try:
59
+ db.close() # Close the database connection
60
+ except:
61
+ import traceback
62
+ traceback.print_exc()
63
+
64
+ return output
65
+
66
+ def get_colors_drawn_over(mask, image_to_analyze, forbidden_colors=[0, 0xFFFFFF]):
67
+ """
68
+ Retrieves the colors drawn over a mask in an image.
69
+
70
+ Args:
71
+ mask (ndarray): The mask indicating the drawn areas.
72
+ image_to_analyze (ndarray): The image to analyze.
73
+ forbidden_colors (list or int, optional): Colors to exclude from the result.
74
+ Defaults to [0, 0xFFFFFF].
75
+
76
+ Returns:
77
+ list: The list of colors drawn over the mask.
78
+
79
+ """
80
+ if mask is None:
81
+ return None
82
+
83
+ selected_colors = image_to_analyze[mask != 0] # Get the colors corresponding to the non-zero regions of the mask
84
+
85
+ if len(image_to_analyze.shape) == 3:
86
+ selected_colors = RGB_to_int24(selected_colors) # Convert RGB colors to int24 format
87
+
88
+ selected_colors = set(selected_colors.ravel().tolist()) # Convert the colors to a set
89
+
90
+ if forbidden_colors is not None:
91
+ if not isinstance(forbidden_colors, list):
92
+ forbidden_colors = [forbidden_colors] # Convert single forbidden color to a list
93
+
94
+ for color in forbidden_colors:
95
+ if color in selected_colors:
96
+ selected_colors.remove(color) # Remove forbidden colors from the selected colors set
97
+
98
+ selected_colors = list(selected_colors) # Convert the set back to a list
99
+
100
+ return selected_colors
101
+
102
+
103
+ def handCorrection_to_label(handCorrection):
104
+ """
105
+ Converts a hand correction image to a labeled image.
106
+
107
+ Args:
108
+ handCorrection (str or ndarray): The hand correction image as a filename or ndarray.
109
+
110
+ Returns:
111
+ ndarray: The labeled image.
112
+
113
+ """
114
+ if isinstance(handCorrection, str):
115
+ handCorrection = Img(handCorrection) # Load the hand correction image if it's a filename
116
+
117
+ if len(handCorrection.shape) == 3:
118
+ handCorrection = handCorrection[..., 0] # Convert RGB image to grayscale
119
+
120
+ handCorrection = label(handCorrection, connectivity=1, background=255) # Label the image
121
+
122
+ return handCorrection
123
+
124
+ def add_coords_to_db(db_path, table_name_to_store_coords_to, coords):
125
+ """
126
+ Adds coordinates to a database table.
127
+
128
+ Args:
129
+ db_path (str): The path to the database.
130
+ table_name_to_store_coords_to (str): The name of the table to store the coordinates.
131
+ coords (list): A list of coordinate tuples in the format (y, x).
132
+
133
+ """
134
+ from batoolset.ta.database.sql import TAsql
135
+
136
+ coords_of_selection = {'pixel_within_cell_y': [], 'pixel_within_cell_x': []}
137
+
138
+ db = None
139
+ try:
140
+ db = TAsql(db_path) # Open the database connection
141
+
142
+ # Extract y and x coordinates from the coordinate tuples and store them in separate lists
143
+ for coord in coords:
144
+ coords_of_selection['pixel_within_cell_y'].append(coord[0])
145
+ coords_of_selection['pixel_within_cell_x'].append(coord[1])
146
+
147
+ # Create a new table or append to an existing table in the database with the coordinate data
148
+ db.create_and_append_table(table_name=table_name_to_store_coords_to, datas=coords_of_selection)
149
+ except:
150
+ traceback.print_exc()
151
+ logger.error('Something went wrong while trying to write coordinates to the database')
152
+ finally:
153
+ if db is not None:
154
+ try:
155
+ db.close() # Close the database connection
156
+ except:
157
+ traceback.print_exc()
158
+
159
+
160
+ def convert_selection_color_to_coords(img_to_analyze_RGB24_or_label, selected_cells, bg_color=None):
161
+ """
162
+ Converts selected cell colors to coordinates within the image.
163
+
164
+ Args:
165
+ img_to_analyze_RGB24_or_label (numpy.ndarray): The image to analyze, either in RGB24 format or label format.
166
+ selected_cells (list): A list of selected cell colors.
167
+ bg_color (int, optional): The background color. If not provided, it will be determined automatically.
168
+
169
+ Returns:
170
+ list: A list of coordinate tuples representing the selected cells.
171
+
172
+ """
173
+ # tmp = img_to_analyze
174
+ coords_of_selection = []
175
+
176
+ if img_to_analyze_RGB24_or_label is None:
177
+ logger.error('No image provided. Nothing to do...')
178
+ return coords_of_selection
179
+
180
+ if len(img_to_analyze_RGB24_or_label.shape) == 3:
181
+ img_to_analyze_RGB24_or_label = RGB_to_int24(img_to_analyze_RGB24_or_label)
182
+
183
+ if bg_color is None:
184
+ if 0xFFFFFF in img_to_analyze_RGB24_or_label:
185
+ bg_color = 0xFFFFFF
186
+ else:
187
+ bg_color = 0
188
+
189
+ cell_label = label(img_to_analyze_RGB24_or_label, connectivity=1, background=bg_color)
190
+
191
+ # For all the selected cells, return the coordinates
192
+ for region in regionprops(cell_label):
193
+ color = img_to_analyze_RGB24_or_label[region.coords[0][0], region.coords[0][1]]
194
+ if color in selected_cells:
195
+ point_always_inside_the_cell = point_on_surface(region, cell_label)
196
+ coords_of_selection.append(point_always_inside_the_cell)
197
+
198
+ return coords_of_selection
199
+
200
+
201
+ def convert_coords_to_IDs(img_to_analyze_RGB24_or_label, selected_coords, forbidden_colors=[0xFFFFFF, 0], return_image=False, new_color_to_give_to_cells_if_return_image=None):
202
+ """
203
+ Converts selected coordinates to cell IDs in the image.
204
+
205
+ Args:
206
+ img_to_analyze_RGB24_or_label (numpy.ndarray): The image to analyze, either in RGB24 format or label format.
207
+ selected_coords (list): A list of selected coordinates.
208
+ forbidden_colors (list, optional): Colors to exclude from conversion. Defaults to [0xFFFFFF, 0].
209
+ return_image (bool, optional): Whether to return an image with converted cell IDs. Defaults to False.
210
+ new_color_to_give_to_cells_if_return_image (int, optional): The color to assign to cells in the returned image. Only applicable if return_image is True.
211
+
212
+ Returns:
213
+ list or numpy.ndarray: A list of cell IDs or an image with converted cell IDs, depending on the return_image parameter.
214
+
215
+ """
216
+ ids = []
217
+
218
+ if img_to_analyze_RGB24_or_label is None:
219
+ logger.error('Empty image. Nothing to do...')
220
+ if return_image:
221
+ return None
222
+ return ids
223
+
224
+ if len(img_to_analyze_RGB24_or_label.shape) == 3:
225
+ img_to_analyze_RGB24_or_label = RGB_to_int24(img_to_analyze_RGB24_or_label)
226
+
227
+ if return_image:
228
+ ids = np.zeros_like(img_to_analyze_RGB24_or_label)
229
+
230
+ for coords in selected_coords:
231
+ color = img_to_analyze_RGB24_or_label[coords[0], coords[1]]
232
+
233
+ if forbidden_colors is not None:
234
+ if color in forbidden_colors:
235
+ continue
236
+
237
+ if not return_image:
238
+ ids.append(color)
239
+ else:
240
+ # Can be used to plot clones
241
+ if new_color_to_give_to_cells_if_return_image is not None:
242
+ ids[img_to_analyze_RGB24_or_label == color] = new_color_to_give_to_cells_if_return_image
243
+ else:
244
+ ids[img_to_analyze_RGB24_or_label == color] = color
245
+
246
+ return ids
247
+
248
+ def convert_selected_cells_to_local_db_coords(selected_cells, label_or_RGB24_image_corresponding_to_selected_cells,
249
+ db_path, table_name_to_store_coords_to, bg_color_for_label=None):
250
+ """
251
+ Converts selected cells to local coordinates and stores them in a database.
252
+
253
+ Args:
254
+ selected_cells (list): List of selected cell IDs.
255
+ label_or_RGB24_image_corresponding_to_selected_cells (numpy.ndarray): The label or RGB24 image corresponding to the selected cells.
256
+ db_path (str): Path to the database.
257
+ table_name_to_store_coords_to (str): Name of the table to store the coordinates.
258
+ bg_color_for_label (int, optional): Background color for label image. Defaults to None.
259
+
260
+ Returns:
261
+ None
262
+
263
+ """
264
+ if not selected_cells:
265
+ logger.error('Nothing selected. Nothing to do.')
266
+ return
267
+
268
+ if bg_color_for_label is None:
269
+ # Auto mode to determine the label
270
+ if 0xFFFFFF in label_or_RGB24_image_corresponding_to_selected_cells:
271
+ bg_color_for_label = 0xFFFFFF
272
+ else:
273
+ bg_color_for_label = 0
274
+
275
+ try:
276
+ cell_label = label(label_or_RGB24_image_corresponding_to_selected_cells, connectivity=1,
277
+ background=bg_color_for_label)
278
+
279
+ coords = []
280
+ for region in regionprops(cell_label):
281
+ color = label_or_RGB24_image_corresponding_to_selected_cells[region.coords[0][0], region.coords[0][1]]
282
+ if color in selected_cells:
283
+ # Get the coordinate always inside the cell and store it in the database
284
+ point_awlays_inside_the_cell = point_on_surface(region, cell_label)
285
+ coords.append(point_awlays_inside_the_cell)
286
+
287
+ # Store the coordinates in the database
288
+ add_coords_to_db(db_path, table_name_to_store_coords_to, coords)
289
+
290
+ except:
291
+ traceback.print_exc()
292
+ logger.error('Something went wrong. Selection could not be converted to 2D coordinates')
293
+
294
+
295
+ if __name__ == '__main__':
296
+ import sys
297
+
298
+ if False:
299
+ # test how to append selection to a clone database
300
+ path_to_image = '/E/Sample_images/sample_images_PA/mini_empty/focused_Series012.png'
301
+ selected_cells = [200, 201, 302] # cells 1-3 have been selected
302
+ handCorrection = Img(smart_name_parser(path_to_image, ordered_output='handCorrection.tif'))
303
+ if len(handCorrection.shape) == 3:
304
+ handCorrection = handCorrection[..., 0]
305
+ cell_label = label(handCorrection, connectivity=1, background=255)
306
+ # print(smart_name_parser(path_to_image, ordered_output='pyTA.db'))
307
+ convert_selected_cells_to_local_db_coords(selected_cells, cell_label,
308
+ smart_name_parser(path_to_image, ordered_output='pyTA.db'),
309
+ 'test_db_name', bg_color_for_label=0) # smart
310
+ # try relaod the coords as an image
311
+ sys.exit(0)
312
+
313
+ # ça marche vraiment bien en fait j'adore!!!
314
+ if True:
315
+ # load database from image and get the corresponding cell image or db depending on what is desired --> TODO
316
+ path_to_image = '/E/Sample_images/sample_images_PA/mini_empty/focused_Series012.png'
317
+ handCorrection = Img(smart_name_parser(path_to_image, ordered_output='handCorrection.tif'))
318
+ if len(handCorrection.shape) == 3:
319
+ handCorrection = handCorrection[..., 0]
320
+ cell_label = label(handCorrection, connectivity=1, background=255)
321
+ output = convert_db_xy_coordiantes_to_local_cell_ID_for_clones(smart_name_parser(path_to_image, ordered_output='pyTA.db'), 'test_db_name', cell_label, return_image=True) #return_image=Fals
322
+ # ça marche vraiment super bien
323
+ if isinstance(output, np.ndarray):
324
+ plt.imshow(output)
325
+ plt.show()
326
+ else:
327
+ print(output)
328
+ # --> this does return cells 1 to 3
329
+ sys.exit(0)
File without changes