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.
- batoolset/GUI/__init__.py +0 -0
- batoolset/GUI/list_gui.py +513 -0
- batoolset/GUI/multi_image_display.py +989 -0
- batoolset/GUI/open.py +325 -0
- batoolset/GUI/overlay_hints.py +45 -0
- batoolset/GUI/paint2.py +1345 -0
- batoolset/GUI/scrollablepaint.py +1152 -0
- batoolset/IJ_ROIs/__init__.py +0 -0
- batoolset/IJ_ROIs/tools.py +40 -0
- batoolset/PATH/__init__.py +0 -0
- batoolset/PATH/tools.py +79 -0
- batoolset/SQLite_tools/__init__.py +0 -0
- batoolset/SQLite_tools/tools.py +840 -0
- batoolset/__init__.py +0 -0
- batoolset/binary/__init__.py +0 -0
- batoolset/binary/tools.py +123 -0
- batoolset/binarytools/__init__.py +0 -0
- batoolset/binarytools/cell_center_detector.py +290 -0
- batoolset/clipboard_tools/__init__.py +0 -0
- batoolset/clipboard_tools/tools.py +7 -0
- batoolset/colors/__init__.py +0 -0
- batoolset/colors/colorgen.py +193 -0
- batoolset/colors/tools.py +22 -0
- batoolset/command_line/__init__.py +0 -0
- batoolset/command_line/tools.py +18 -0
- batoolset/dialogs/__init__.py +0 -0
- batoolset/dialogs/opensave.py +228 -0
- batoolset/dicts/__init__.py +0 -0
- batoolset/dicts/tools.py +299 -0
- batoolset/dims/__init__.py +0 -0
- batoolset/dims/tools.py +83 -0
- batoolset/draw/__init__.py +0 -0
- batoolset/draw/shapes/Position.py +183 -0
- batoolset/draw/shapes/__init__.py +0 -0
- batoolset/draw/shapes/automated_alignment_drawing_refactored.py +346 -0
- batoolset/draw/shapes/circle2d.py +99 -0
- batoolset/draw/shapes/compute_optimal_size_all_merged.py +317 -0
- batoolset/draw/shapes/ellipse2d.py +336 -0
- batoolset/draw/shapes/freehand2d.py +235 -0
- batoolset/draw/shapes/group.py +1830 -0
- batoolset/draw/shapes/image2d.py +2469 -0
- batoolset/draw/shapes/line2d.py +575 -0
- batoolset/draw/shapes/point2d.py +257 -0
- batoolset/draw/shapes/polygon2d.py +357 -0
- batoolset/draw/shapes/polyline2d.py +235 -0
- batoolset/draw/shapes/rect2d.py +388 -0
- batoolset/draw/shapes/rectangle2d.py +601 -0
- batoolset/draw/shapes/scalebar.py +304 -0
- batoolset/draw/shapes/serializablefont.py +126 -0
- batoolset/draw/shapes/serializableguiparams.py +10 -0
- batoolset/draw/shapes/square2d.py +103 -0
- batoolset/draw/shapes/textorientation.py +45 -0
- batoolset/draw/shapes/tools.py +467 -0
- batoolset/draw/shapes/transform2D.py +350 -0
- batoolset/draw/shapes/txt2d.py +550 -0
- batoolset/draw/widgets/__init__.py +0 -0
- batoolset/draw/widgets/col.py +343 -0
- batoolset/draw/widgets/image_group.py +248 -0
- batoolset/draw/widgets/image_organizer.py +96 -0
- batoolset/draw/widgets/paint.py +184 -0
- batoolset/draw/widgets/vectorial.py +257 -0
- batoolset/figure/__init__.py +0 -0
- batoolset/figure/alignment.py +814 -0
- batoolset/figure/column.py +1117 -0
- batoolset/figure/fig_tools.py +285 -0
- batoolset/figure/minimal_debugger_scale_etc.py +139 -0
- batoolset/figure/panel.py +697 -0
- batoolset/figure/row.py +852 -0
- batoolset/figure/user_selection.py +287 -0
- batoolset/files/__init__.py +0 -0
- batoolset/files/tools.py +1321 -0
- batoolset/images/__init__.py +0 -0
- batoolset/images/tools.py +81 -0
- batoolset/img.py +5216 -0
- batoolset/linux/__init__.py +0 -0
- batoolset/linux/tools.py +72 -0
- batoolset/lists/__init__.py +0 -0
- batoolset/lists/tools.py +436 -0
- batoolset/luts/__init__.py +0 -0
- batoolset/luts/lut_minimal_test.py +1207 -0
- batoolset/matplolib/__init__.py +0 -0
- batoolset/matplolib/tools.py +44 -0
- batoolset/np_tools/__init__.py +0 -0
- batoolset/np_tools/tools.py +252 -0
- batoolset/np_tools/trash.py +15 -0
- batoolset/pandas_tools/__init__.py +0 -0
- batoolset/pandas_tools/tools.py +880 -0
- batoolset/partials/__init__.py +0 -0
- batoolset/partials/tools.py +83 -0
- batoolset/plot_tools/__init__.py +0 -0
- batoolset/plot_tools/tools.py +70 -0
- batoolset/pyqt/__init__.py +0 -0
- batoolset/pyqt/tools.py +691 -0
- batoolset/re_tools/__init__.py +0 -0
- batoolset/re_tools/tools.py +35 -0
- batoolset/serialization/__init__.py +0 -0
- batoolset/serialization/tools.py +1192 -0
- batoolset/sets/__init__.py +0 -0
- batoolset/sets/tools.py +109 -0
- batoolset/settings/__init__.py +0 -0
- batoolset/settings/global_settings.py +134 -0
- batoolset/strings/__init__.py +0 -0
- batoolset/strings/tools.py +225 -0
- batoolset/ta/__init__.py +0 -0
- batoolset/ta/database/__init__.py +0 -0
- batoolset/ta/database/advanced_sql_plotter.py +1170 -0
- batoolset/ta/database/my_qt_table.py +79 -0
- batoolset/ta/database/preview_and_edit_sqlite_db.py +405 -0
- batoolset/ta/database/sql.py +2141 -0
- batoolset/ta/database/sql_column_name_dialog.py +122 -0
- batoolset/ta/measurements/TAmeasures.py +2226 -0
- batoolset/ta/measurements/__init__.py +0 -0
- batoolset/ta/measurements/measurements3D/__init__.py +0 -0
- batoolset/ta/measurements/measurements3D/get_point_on_surface_if_centroid_is_bad.py +175 -0
- batoolset/ta/measurements/measurements3D/height_map_to_projection.py +82 -0
- batoolset/ta/measurements/measurements3D/measures3D.py +208 -0
- batoolset/ta/measurements/measurements3D/triangulate.py +331 -0
- batoolset/ta/measurements/nematic.py +562 -0
- batoolset/ta/measurements/nematic_measurements.py +107 -0
- batoolset/ta/segmentation/__init__.py +0 -0
- batoolset/ta/segmentation/neo_wshed.py +314 -0
- batoolset/ta/selections/__init__.py +0 -0
- batoolset/ta/selections/selection.py +329 -0
- batoolset/ta/tracking/__init__.py +0 -0
- batoolset/ta/tracking/last_tracking_based_on_matching_or_on_translation_from_mermaid_warp.py +653 -0
- batoolset/ta/tracking/local_to_track_correspondance.py +138 -0
- batoolset/ta/tracking/rapid_detection_of_vertices.py +517 -0
- batoolset/ta/tracking/registration.py +108 -0
- batoolset/ta/tracking/swap_detector_and_fixer.py +296 -0
- batoolset/ta/tracking/track_correction.py +238 -0
- batoolset/ta/tracking/tracking_error_detector_and_fixer.py +3099 -0
- batoolset/ta/tracking/tracking_yet_another_approach_pyramidal_registration_n_neo_swapping_correction.py +725 -0
- batoolset/ta/utils/TA_tools.py +43 -0
- batoolset/ta/utils/__init__.py +0 -0
- batoolset/ta/utils/rps_tools.py +1783 -0
- batoolset/tests/__init__.py +0 -0
- batoolset/tests/rps_tools.py +51 -0
- batoolset/tests/tools.py +10 -0
- batoolset/tools/__init__.py +0 -0
- batoolset/tools/early_stopper_class.py +9 -0
- batoolset/tools/guided_data_recoverer.py +110 -0
- batoolset/tools/logger.py +100 -0
- batoolset/tools/mytimer.py +31 -0
- batoolset/tools/prompt_color.py +160 -0
- batoolset/tools/qthandler.py +118 -0
- batoolset/uitools/__init__.py +0 -0
- batoolset/uitools/blinker.py +56 -0
- batoolset/unsafe/__init__.py +0 -0
- batoolset/unsafe/tools.py +115 -0
- batoolset/utils/__init__.py +0 -0
- batoolset/utils/commontools.py +158 -0
- batoolset/utils/loadlist.py +728 -0
- batoolset/version.py +10 -0
- batoolset/xml/__init__.py +0 -0
- batoolset/xml/tools.py +65 -0
- batoolset/zip_tools/__init__.py +0 -0
- batoolset/zip_tools/tools.py +76 -0
- batoolset-0.1.0.dist-info/LICENSE +24 -0
- batoolset-0.1.0.dist-info/METADATA +45 -0
- batoolset-0.1.0.dist-info/RECORD +162 -0
- batoolset-0.1.0.dist-info/WHEEL +5 -0
- 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
|