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,2226 @@
|
|
|
1
|
+
import math
|
|
2
|
+
import os.path
|
|
3
|
+
from multiprocessing import Pool
|
|
4
|
+
from scipy import ndimage
|
|
5
|
+
import random
|
|
6
|
+
from scipy.spatial.distance import squareform
|
|
7
|
+
from skimage.measure._regionprops import RegionProperties
|
|
8
|
+
from batoolset.img import Img, pad_border_xy
|
|
9
|
+
from skimage.measure import label, regionprops
|
|
10
|
+
import numpy as np
|
|
11
|
+
import traceback
|
|
12
|
+
from batoolset.ta.measurements.nematic import compute_stretch_nematic
|
|
13
|
+
from batoolset.tools.early_stopper_class import early_stop
|
|
14
|
+
from batoolset.utils.loadlist import loadlist
|
|
15
|
+
from batoolset.ta.database.sql import TAsql, get_property
|
|
16
|
+
from batoolset.ta.segmentation.neo_wshed import wshed
|
|
17
|
+
# from epyseg.ta.clones.clone_fuser import distance_between_points
|
|
18
|
+
from batoolset.ta.measurements.nematic_measurements import compute_polarity_nematic
|
|
19
|
+
from batoolset.ta.measurements.measurements3D.get_point_on_surface_if_centroid_is_bad import point_on_surface
|
|
20
|
+
from batoolset.ta.measurements.measurements3D.measures3D import compute_3D_surfacearea, perimeter_3D
|
|
21
|
+
from batoolset.ta.measurements.measurements3D.triangulate import triangulate
|
|
22
|
+
from batoolset.ta.tracking.rapid_detection_of_vertices import detect_vertices_and_bonds, cantor_color_bonds, neighbors8
|
|
23
|
+
from timeit import default_timer as timer
|
|
24
|
+
from batoolset.files.tools import smart_name_parser
|
|
25
|
+
from batoolset.ta.tracking.tracking_error_detector_and_fixer import get_border_cells, get_border_cells_plus_one, \
|
|
26
|
+
get_cells_and_their_neighbors_from_image
|
|
27
|
+
from batoolset.ta.utils.rps_tools import pavlidis, compute_distance_between_consecutive_points
|
|
28
|
+
import math
|
|
29
|
+
from math import sqrt
|
|
30
|
+
from batoolset.tools.logger import TA_logger # logging
|
|
31
|
+
|
|
32
|
+
logger = TA_logger()
|
|
33
|
+
|
|
34
|
+
__DEBUG__ = False
|
|
35
|
+
|
|
36
|
+
import numpy as np
|
|
37
|
+
from math import sqrt, atan, degrees
|
|
38
|
+
from skimage.measure import label, regionprops
|
|
39
|
+
|
|
40
|
+
def distance_between_points_deprecated(p1, p2):
|
|
41
|
+
"""
|
|
42
|
+
Deprecated function to compute the distance between two points in 2D.
|
|
43
|
+
|
|
44
|
+
Args:
|
|
45
|
+
p1 (tuple): First point coordinates (x, y).
|
|
46
|
+
p2 (tuple): Second point coordinates (x, y).
|
|
47
|
+
|
|
48
|
+
Returns:
|
|
49
|
+
float: Distance between the points.
|
|
50
|
+
|
|
51
|
+
"""
|
|
52
|
+
return sqrt((p1[0] - p2[0]) ** 2 + (p1[1] - p2[1]) ** 2)
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
def distance_between_points_nD(p1, p2, rescaling_factor=None):
|
|
56
|
+
"""
|
|
57
|
+
Computes the distance between two points in n-dimensional space.
|
|
58
|
+
|
|
59
|
+
Args:
|
|
60
|
+
p1 (numpy.ndarray): First point coordinates.
|
|
61
|
+
p2 (numpy.ndarray): Second point coordinates.
|
|
62
|
+
rescaling_factor (float, optional): Rescaling factor for real distance computation. Defaults to None.
|
|
63
|
+
|
|
64
|
+
Returns:
|
|
65
|
+
float: Distance between the points.
|
|
66
|
+
|
|
67
|
+
Examples:
|
|
68
|
+
>>> p1 = np.array([1, 2, 3])
|
|
69
|
+
>>> p2 = np.array([4, 5, 6])
|
|
70
|
+
>>> distance_between_points_nD(p1, p2)
|
|
71
|
+
5.196152422706632
|
|
72
|
+
|
|
73
|
+
"""
|
|
74
|
+
return distance_between_points(p1, p2, rescaling_factor=rescaling_factor)
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
def distance_between_points(p1, p2, rescaling_factor=None):
|
|
78
|
+
"""
|
|
79
|
+
Computes n-dimensional distance between points (2D, 3D, nD) and can return real distance instead of pixel distance
|
|
80
|
+
when the optional rescaling_factor is set.
|
|
81
|
+
|
|
82
|
+
Args:
|
|
83
|
+
p1 (numpy.ndarray): First point coordinates.
|
|
84
|
+
p2 (numpy.ndarray): Second point coordinates.
|
|
85
|
+
rescaling_factor (numpy.ndarray, optional): Voxel scaling factors corresponding to the dimensions. Defaults to None.
|
|
86
|
+
|
|
87
|
+
Returns:
|
|
88
|
+
float: Distance between the points.
|
|
89
|
+
|
|
90
|
+
Examples:
|
|
91
|
+
>>> p1 = np.array([1, 2, 3])
|
|
92
|
+
>>> p2 = np.array([4, 5, 6])
|
|
93
|
+
>>> distance_between_points(p1, p2)
|
|
94
|
+
5.196152422706632
|
|
95
|
+
>>> p1 = np.array([1, 2, 3])
|
|
96
|
+
>>> p2 = np.array([4, 5, 6])
|
|
97
|
+
>>> rescaling_factor = [0.0691888, 0.0691888, 0.2500000] # e.g. conversion of pixels to µm
|
|
98
|
+
>>> distance_between_points(p1, p2, rescaling_factor) # dist in µm
|
|
99
|
+
0.8053990444605208
|
|
100
|
+
>>> p1 = np.array([[1, 2, 3],[4, 5, 6]])
|
|
101
|
+
>>> p2 = np.array([[1, 2, 3],[4, 5, 6]])
|
|
102
|
+
>>> rescaling_factor = [0.0691888, 0.0691888, 0.2500000] # e.g. conversion of pixels to µm
|
|
103
|
+
>>> distance_between_points(p1, p2, rescaling_factor) # dist in µm
|
|
104
|
+
array([0., 0.])
|
|
105
|
+
>>> p1 = np.array([[4, 5, 6],[1, 2, 3]])
|
|
106
|
+
>>> p2 = np.array([[1, 2, 3],[4, 5, 6]])
|
|
107
|
+
>>> rescaling_factor = [0.0691888, 0.0691888, 0.2500000] # e.g. conversion of pixels to µm
|
|
108
|
+
>>> distance_between_points(p1, p2, rescaling_factor) # dist in µm
|
|
109
|
+
array([0.80539904, 0.80539904])
|
|
110
|
+
"""
|
|
111
|
+
|
|
112
|
+
if not isinstance(p1, np.ndarray):
|
|
113
|
+
p1 = np.asarray(p1)
|
|
114
|
+
if not isinstance(p2, np.ndarray):
|
|
115
|
+
p2 = np.asarray(p2)
|
|
116
|
+
|
|
117
|
+
if rescaling_factor is not None:
|
|
118
|
+
p1 = p1 * rescaling_factor
|
|
119
|
+
p2 = p2 * rescaling_factor
|
|
120
|
+
|
|
121
|
+
# that should always work but is that True --> do tests
|
|
122
|
+
axis = 0
|
|
123
|
+
if len(p1.shape)==2:
|
|
124
|
+
axis=1
|
|
125
|
+
return np.sqrt(np.sum(np.square(p1 - p2), axis=axis))
|
|
126
|
+
|
|
127
|
+
|
|
128
|
+
|
|
129
|
+
def get_sum_and_avg_intensity(original_image, reg, idx=None, y_shift_to_transform_local_coords_to_global_coords=0,
|
|
130
|
+
x_shift_to_transform_local_coords_to_global_coords=0):
|
|
131
|
+
"""
|
|
132
|
+
Computes the sum and average intensity of a region in an image.
|
|
133
|
+
|
|
134
|
+
Args:
|
|
135
|
+
original_image (numpy.ndarray): Original image.
|
|
136
|
+
reg (numpy.ndarray or regionprops): Region of interest.
|
|
137
|
+
idx (int, optional): Index of the region if reg is a list of regionprops. Defaults to None.
|
|
138
|
+
y_shift_to_transform_local_coords_to_global_coords (int, optional): Y shift to transform local coordinates to global coordinates. Defaults to 0.
|
|
139
|
+
x_shift_to_transform_local_coords_to_global_coords (int, optional): X shift to transform local coordinates to global coordinates. Defaults to 0.
|
|
140
|
+
|
|
141
|
+
Returns:
|
|
142
|
+
tuple: Sum and average intensity of the region.
|
|
143
|
+
|
|
144
|
+
# Examples:
|
|
145
|
+
# >>> image = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]])
|
|
146
|
+
# >>> region = np.array([[0, 0], [1, 1]])
|
|
147
|
+
# >>> get_sum_and_avg_intensity(image, region)
|
|
148
|
+
# (6, 3.0)
|
|
149
|
+
|
|
150
|
+
"""
|
|
151
|
+
if len(original_image.shape) >= 3:
|
|
152
|
+
axis = 0
|
|
153
|
+
else:
|
|
154
|
+
axis = None
|
|
155
|
+
|
|
156
|
+
if idx is not None:
|
|
157
|
+
final_reg = reg[idx]
|
|
158
|
+
else:
|
|
159
|
+
final_reg = reg
|
|
160
|
+
|
|
161
|
+
if isinstance(final_reg, RegionProperties):
|
|
162
|
+
ys = final_reg.coords[:, 0]
|
|
163
|
+
xs = final_reg.coords[:, 1]
|
|
164
|
+
else:
|
|
165
|
+
ys = final_reg[:, 0]
|
|
166
|
+
xs = final_reg[:, 1]
|
|
167
|
+
|
|
168
|
+
sum_bd_intensity = np.sum(original_image[
|
|
169
|
+
ys + y_shift_to_transform_local_coords_to_global_coords,
|
|
170
|
+
xs + x_shift_to_transform_local_coords_to_global_coords],
|
|
171
|
+
axis=axis)
|
|
172
|
+
avg_bd_intensity = sum_bd_intensity / float(len(xs))
|
|
173
|
+
|
|
174
|
+
return sum_bd_intensity, avg_bd_intensity
|
|
175
|
+
|
|
176
|
+
|
|
177
|
+
def get_orientation(first_vertex, second_vertex):
|
|
178
|
+
"""
|
|
179
|
+
Computes the orientation (in degrees) between two vertices.
|
|
180
|
+
|
|
181
|
+
Args:
|
|
182
|
+
first_vertex (tuple): First vertex coordinates (x, y).
|
|
183
|
+
second_vertex (tuple): Second vertex coordinates (x, y).
|
|
184
|
+
|
|
185
|
+
Returns:
|
|
186
|
+
float: Orientation between the vertices.
|
|
187
|
+
|
|
188
|
+
Examples:
|
|
189
|
+
>>> v1 = (1, 2)
|
|
190
|
+
>>> v2 = (4, 5)
|
|
191
|
+
>>> get_orientation(v1, v2)
|
|
192
|
+
45.0
|
|
193
|
+
|
|
194
|
+
"""
|
|
195
|
+
bd_orientation = degrees(atan_RAD(first_vertex[0] - second_vertex[0], first_vertex[1] - second_vertex[1]))
|
|
196
|
+
while bd_orientation >= 180.:
|
|
197
|
+
bd_orientation -= 180.
|
|
198
|
+
return bd_orientation
|
|
199
|
+
|
|
200
|
+
def atan_RAD(y, x):
|
|
201
|
+
"""
|
|
202
|
+
Computes the arctangent of y/x in radians, taking into account the quadrant.
|
|
203
|
+
|
|
204
|
+
Args:
|
|
205
|
+
y (float): y-coordinate.
|
|
206
|
+
x (float): x-coordinate.
|
|
207
|
+
|
|
208
|
+
Returns:
|
|
209
|
+
float: Arctangent value in radians.
|
|
210
|
+
|
|
211
|
+
Notes:
|
|
212
|
+
This function uses a custom implementation to handle the quadrant correctly.
|
|
213
|
+
|
|
214
|
+
"""
|
|
215
|
+
if abs(x) == 0.:
|
|
216
|
+
return math.pi / 2.
|
|
217
|
+
res = math.atan(abs(y) / abs(x))
|
|
218
|
+
res = math.pi - res if x <= 0. and y > 0. else res
|
|
219
|
+
res = math.pi + res if x <= 0. and y <= 0. else res
|
|
220
|
+
res = 2. * math.pi - res if x > 0. and y <= 0. else res
|
|
221
|
+
return res
|
|
222
|
+
|
|
223
|
+
|
|
224
|
+
def fill_missing_with_Nones(database):
|
|
225
|
+
"""
|
|
226
|
+
Fills missing entries in a database dictionary with None values.
|
|
227
|
+
|
|
228
|
+
Args:
|
|
229
|
+
database (dict): Database dictionary.
|
|
230
|
+
|
|
231
|
+
Returns:
|
|
232
|
+
dict: Updated database with missing entries filled with None.
|
|
233
|
+
|
|
234
|
+
"""
|
|
235
|
+
max_length = 0
|
|
236
|
+
for k, v in database.items():
|
|
237
|
+
max_length = max(max_length, len(v))
|
|
238
|
+
for k, v in database.items():
|
|
239
|
+
if len(v) != max_length:
|
|
240
|
+
missing = [None] * (max_length - len(v))
|
|
241
|
+
v.extend(missing)
|
|
242
|
+
return database
|
|
243
|
+
|
|
244
|
+
def TAMeasurements(file_or_list, __forced_orig=None, __forced_cells=None, __forced_heightmap=None,
|
|
245
|
+
measure_polarity=False, measure_3D=False, min_cell_size=10, progress_callback=None,
|
|
246
|
+
bond_cut_off=2, multi_threading=True): # if less or equal to 2 --> is not a bond but is a vertex
|
|
247
|
+
|
|
248
|
+
# print('file_or_list', type(file_or_list))
|
|
249
|
+
# we MT the whole stuff because it's fairly easy to do so
|
|
250
|
+
if isinstance(file_or_list, list):
|
|
251
|
+
start = timer()
|
|
252
|
+
if multi_threading:
|
|
253
|
+
from tqdm import tqdm
|
|
254
|
+
from functools import partial
|
|
255
|
+
import sys
|
|
256
|
+
import multiprocessing
|
|
257
|
+
import gc
|
|
258
|
+
# given that python copies all the content of the memory for multiprocessing, it's probably a good idea to clean it up
|
|
259
|
+
gc.collect()
|
|
260
|
+
# import platform
|
|
261
|
+
#
|
|
262
|
+
# if platform.system() == "Darwin":
|
|
263
|
+
# multiprocessing.set_start_method('spawn')
|
|
264
|
+
|
|
265
|
+
nb_procs = multiprocessing.cpu_count()-1
|
|
266
|
+
if nb_procs<=0:
|
|
267
|
+
nb_procs = 1
|
|
268
|
+
print('using',nb_procs, 'processors')
|
|
269
|
+
|
|
270
|
+
# nb none of these alternatives work on macOS X... I guess this may have to do that I am launching threads from within a pyqt thread which may not be a good idea
|
|
271
|
+
# from concurrent.futures import ThreadPoolExecutor
|
|
272
|
+
# from concurrent.futures import ProcessPoolExecutor
|
|
273
|
+
with Pool(processes=nb_procs) as pool:
|
|
274
|
+
# with ThreadPoolExecutor(max_workers=nb_procs) as pool:
|
|
275
|
+
# with ProcessPoolExecutor(max_workers=nb_procs) as pool:
|
|
276
|
+
# pool = Pool(processes=nb_procs)
|
|
277
|
+
process = partial(TAMeasurements, measure_polarity=measure_polarity, measure_3D=measure_3D,
|
|
278
|
+
min_cell_size=min_cell_size, bond_cut_off=bond_cut_off)
|
|
279
|
+
for i, _ in enumerate(tqdm(pool.imap_unordered(process, file_or_list), total=len(file_or_list))):
|
|
280
|
+
# for i, _ in enumerate(tqdm(pool.map(process, file_or_list), total=len(file_or_list))): # does not work with threadpool executor I am doing smthg wrong ???
|
|
281
|
+
# pass
|
|
282
|
+
# sys.stderr.write('\rdone {0:%}'.format(i / len(merge_names))) # --> I could use that to plot with the other progressbar --> ok
|
|
283
|
+
# cool --> I can use that to display progress in the other progress bar --> the QT one
|
|
284
|
+
# pass
|
|
285
|
+
if early_stop.stop:
|
|
286
|
+
# for multiprocpool
|
|
287
|
+
pool.close()
|
|
288
|
+
pool.join()
|
|
289
|
+
return
|
|
290
|
+
if progress_callback is not None:
|
|
291
|
+
progress_callback.emit(int((i / len(file_or_list)) * 100))
|
|
292
|
+
|
|
293
|
+
# not sure I should put the lines below...
|
|
294
|
+
# https://stackoverflow.com/questions/38271547/when-should-we-call-multiprocessing-pool-join --> maybe still a good idea to keep that
|
|
295
|
+
# for multiprocpool
|
|
296
|
+
pool.close()
|
|
297
|
+
pool.join()
|
|
298
|
+
print('total time', timer() - start)
|
|
299
|
+
return
|
|
300
|
+
else:
|
|
301
|
+
for iii, file in enumerate(file_or_list):
|
|
302
|
+
try:
|
|
303
|
+
if early_stop.stop:
|
|
304
|
+
return
|
|
305
|
+
if progress_callback is not None:
|
|
306
|
+
progress_callback.emit(int((iii / len(file_or_list)) * 100))
|
|
307
|
+
else:
|
|
308
|
+
print(str((iii / len(file_or_list)) * 100) + '%')
|
|
309
|
+
except:
|
|
310
|
+
pass
|
|
311
|
+
try:
|
|
312
|
+
TAMeasurements(file, measure_polarity=measure_polarity, measure_3D=measure_3D,
|
|
313
|
+
min_cell_size=min_cell_size, bond_cut_off=bond_cut_off)
|
|
314
|
+
except:
|
|
315
|
+
if __DEBUG__:
|
|
316
|
+
print('an error occurred while processing file ' + str(file))
|
|
317
|
+
traceback.print_exc()
|
|
318
|
+
logger.error('an error occurred while processing file ' + str(file))
|
|
319
|
+
print('total time', timer() - start)
|
|
320
|
+
return
|
|
321
|
+
|
|
322
|
+
start = timer()
|
|
323
|
+
|
|
324
|
+
|
|
325
|
+
if __DEBUG__:
|
|
326
|
+
print('processing file',file_or_list)
|
|
327
|
+
#
|
|
328
|
+
bonds_associated_to_a_given_cell = {}
|
|
329
|
+
bond_lengths_associated_to_a_given_cell = {}
|
|
330
|
+
local_bond_ID_and_px_count = {}
|
|
331
|
+
|
|
332
|
+
TA_path = None
|
|
333
|
+
db_path = None
|
|
334
|
+
|
|
335
|
+
# original_image = Img('/E/Sample_images/sample_images_PA/mini/focused_Series012.png')[..., 1]
|
|
336
|
+
|
|
337
|
+
if early_stop.stop == True:
|
|
338
|
+
# print('early stop')
|
|
339
|
+
return
|
|
340
|
+
|
|
341
|
+
# instantiate the different databases
|
|
342
|
+
|
|
343
|
+
# some will be dynamically added such as the channels --> but will be a pb if several images have different channel nb --> think about an easy fix ???
|
|
344
|
+
# things from TA that also need be added
|
|
345
|
+
|
|
346
|
+
# TO BE ADDED vx_coords_cells sum_px_intensity_cells_ch1 S1_stretch_cells vx_coords_cells orientation_cells ALSO NEED CENTER OF MASS FOR EACH CHANNEL!!! sum_px_intensity_perimeter_ch1 P1_polarity_ch1 P1_polarity_ch1_normalized V1_polarity_ch1 x_centroid_intensity_weighted_ch1 local_id_of_bonds
|
|
347
|
+
vertices_2D = {'local_ID': [],
|
|
348
|
+
'x': [],
|
|
349
|
+
'y': [],
|
|
350
|
+
'is_border': [],
|
|
351
|
+
'is_border_plus_one': [],
|
|
352
|
+
}
|
|
353
|
+
# axis_major_length
|
|
354
|
+
# axis_minor_length
|
|
355
|
+
# eccentricity
|
|
356
|
+
# orientation ranging from -pi/2 to pi/2 counter-clockwise.
|
|
357
|
+
cells_2D = {'local_ID': [],
|
|
358
|
+
'cytoplasmic_area': [],
|
|
359
|
+
'area': [],
|
|
360
|
+
# 'major_axis_length': [],
|
|
361
|
+
# 'minor_axis_length': [],
|
|
362
|
+
'orientation': [],
|
|
363
|
+
'elongation': [],
|
|
364
|
+
'S1': [],
|
|
365
|
+
'S2': [],
|
|
366
|
+
'pixel_within_cell_x': [],
|
|
367
|
+
'pixel_within_cell_y': [],
|
|
368
|
+
'centroid_x': [],
|
|
369
|
+
'centroid_y': [],
|
|
370
|
+
'first_pixel_x': [],
|
|
371
|
+
'first_pixel_y': [],
|
|
372
|
+
'perimeter': [],
|
|
373
|
+
'perimeter_pixel_count': [],
|
|
374
|
+
'vertices': [],
|
|
375
|
+
'nb_of_vertices_or_neighbours': [],
|
|
376
|
+
'nb_of_vertices_or_neighbours_cut_off': [],
|
|
377
|
+
'bond_cut_off': [], # --> same as bd_size_cut_off in TA
|
|
378
|
+
'bonds': [],
|
|
379
|
+
'is_border': [],
|
|
380
|
+
# formerly is_border_cell --> smarter this way so that I can have the same code for all the databases
|
|
381
|
+
'is_border_plus_one': [], # TODO
|
|
382
|
+
} # local_id_cells --> do I need that instead --> think about it
|
|
383
|
+
cells_3D = {'local_ID': [],
|
|
384
|
+
# 'centroid_z': [], # in fact does that make sense to have that and there are several ways to get it --> wait and see if users or I need and implement it the smart way then
|
|
385
|
+
# 'pixel_within_cell_z': [], # in fact does that make sense to have that and there are several ways to get it --> wait and see if users or I need and implement it the smart way then
|
|
386
|
+
'area3D': [],
|
|
387
|
+
# NB adding 3D is smarter for using proper natural join because otherwise it does not work well
|
|
388
|
+
'area_flat_height': [],
|
|
389
|
+
'perimeter3D': [],
|
|
390
|
+
}
|
|
391
|
+
# TO BE ADDED TO BONDS DYNAMICALLY: sum_px_int_vertices_excluded_ch1 sum_px_int_vertices_included_ch1
|
|
392
|
+
bonds_2D = {'local_ID': [],
|
|
393
|
+
'length': [],
|
|
394
|
+
'pixel_count': [],
|
|
395
|
+
'orientation': [],
|
|
396
|
+
# 'vx_1_x': [],
|
|
397
|
+
# 'vx_1_y': [],
|
|
398
|
+
# 'vx_2_x': [],
|
|
399
|
+
# 'vx_2_y': [],
|
|
400
|
+
'vx_1': [],
|
|
401
|
+
'vx_2': [],
|
|
402
|
+
'first_pixel_x': [],
|
|
403
|
+
'first_pixel_y': [],
|
|
404
|
+
'cell_id1_around_bond': [],
|
|
405
|
+
'cell_id2_around_bond': [],
|
|
406
|
+
'is_border': [], # is_border_bond # new addition but can be useful
|
|
407
|
+
'is_border_plus_one': [],
|
|
408
|
+
}
|
|
409
|
+
bonds_3D = {'local_ID': [],
|
|
410
|
+
'length3D': [],
|
|
411
|
+
'vx_1_z': [], # do I want that --> yes, may be useful in fact...
|
|
412
|
+
'vx_2_z': [],
|
|
413
|
+
# 'first_pixel_z': [],
|
|
414
|
+
}
|
|
415
|
+
# see what else I can add and how I can handle all of these things myself
|
|
416
|
+
# cells_2D
|
|
417
|
+
|
|
418
|
+
if __DEBUG__:
|
|
419
|
+
print('debug #1')
|
|
420
|
+
|
|
421
|
+
# TODO handle several channels for polarity and alike
|
|
422
|
+
if __forced_orig is not None:
|
|
423
|
+
original_image = __forced_orig # if no shift max and min should always be 255 otherwise there is an error somewhere
|
|
424
|
+
else:
|
|
425
|
+
original_image = Img(file_or_list)
|
|
426
|
+
TA_path = smart_name_parser(file_or_list, ordered_output='full_no_ext')
|
|
427
|
+
db_path = os.path.join(TA_path, 'pyTA.db')
|
|
428
|
+
|
|
429
|
+
# if this path is None then debug --> display the image otherwise save it then save stuff
|
|
430
|
+
|
|
431
|
+
cells = None
|
|
432
|
+
if __forced_cells is not None:
|
|
433
|
+
cells = __forced_cells # TODO --> hack this
|
|
434
|
+
if len(cells.shape) >= 3:
|
|
435
|
+
cells = cells[..., 0]
|
|
436
|
+
else:
|
|
437
|
+
handCorrection1, handCorrection2 = smart_name_parser(file_or_list,
|
|
438
|
+
ordered_output=['handCorrection.png',
|
|
439
|
+
'handCorrection.tif'])
|
|
440
|
+
if os.path.isfile(handCorrection2):
|
|
441
|
+
cells = Img(handCorrection2)
|
|
442
|
+
elif os.path.isfile(handCorrection1):
|
|
443
|
+
cells = Img(handCorrection1)
|
|
444
|
+
if cells is None:
|
|
445
|
+
if __DEBUG__:
|
|
446
|
+
print('File not found ' + str(handCorrection2) + ' please segment the images first')
|
|
447
|
+
logger.error('File not found ' + str(handCorrection2) + ' please segment the images first')
|
|
448
|
+
return
|
|
449
|
+
if len(cells.shape) >= 3:
|
|
450
|
+
cells = cells[..., 0]
|
|
451
|
+
|
|
452
|
+
if __DEBUG__:
|
|
453
|
+
print('debug #2')
|
|
454
|
+
|
|
455
|
+
# I need add a border to this image otherwise there will be a bug --> must be done in any case
|
|
456
|
+
if min_cell_size is not None and min_cell_size > 0:
|
|
457
|
+
# plt.imshow(cells)
|
|
458
|
+
# plt.show()
|
|
459
|
+
cells = wshed(cells, seeds='mask', min_seed_area=min_cell_size) # restore border
|
|
460
|
+
# plt.imshow(cells)
|
|
461
|
+
# plt.show()
|
|
462
|
+
|
|
463
|
+
# add a fake border to the image --> that is absolutely necessary !!! --> KEEP
|
|
464
|
+
cells = pad_border_xy(cells, mode=255) # add a wite border to the seg mask
|
|
465
|
+
# plt.imshow(cells)
|
|
466
|
+
# plt.show()
|
|
467
|
+
|
|
468
|
+
# need save the mask
|
|
469
|
+
if TA_path is not None:
|
|
470
|
+
Img(cells, dimensions='hw').save(os.path.join(TA_path,
|
|
471
|
+
'handCorrection.tif')) # TODO --> replace this with a clean save function because that is a bit complicated what i do here!!!
|
|
472
|
+
else:
|
|
473
|
+
# plt.imshow(cells)
|
|
474
|
+
# plt.show()
|
|
475
|
+
pass
|
|
476
|
+
|
|
477
|
+
|
|
478
|
+
if __DEBUG__:
|
|
479
|
+
print('debug #3')
|
|
480
|
+
|
|
481
|
+
# TODO also store vertices and bonds ids --> a quite good idea in fact --> can be used for plots --> fairly good idea
|
|
482
|
+
|
|
483
|
+
height_map = None
|
|
484
|
+
if measure_3D:
|
|
485
|
+
if __forced_heightmap is not None:
|
|
486
|
+
height_map = __forced_heightmap
|
|
487
|
+
else:
|
|
488
|
+
height_map_file = smart_name_parser(file_or_list, ordered_output=['height_map.tif'])[0]
|
|
489
|
+
|
|
490
|
+
# ideally should apply the rescaling factor to the heightmap if any or assume rescaling factor is 1 --> see and make sure everything is done in there
|
|
491
|
+
if os.path.isfile(height_map_file):
|
|
492
|
+
try:
|
|
493
|
+
height_map = Img(height_map_file)
|
|
494
|
+
if db_path is not None:
|
|
495
|
+
try:
|
|
496
|
+
voxel_z_over_x_ratio = get_property(db_path, 'voxel_z_over_x_ratio') # imp
|
|
497
|
+
except:
|
|
498
|
+
if __DEBUG__:
|
|
499
|
+
print('voxel_z_over_x_ratio property not found in the db "' + str(
|
|
500
|
+
db_path) + '", assuming scaling factor is 1, which is very unlikely.')
|
|
501
|
+
logger.warning('voxel_z_over_x_ratio property not found in the db "' + str(
|
|
502
|
+
db_path) + '", assuming scaling factor is 1, which is very unlikely.')
|
|
503
|
+
else:
|
|
504
|
+
voxel_z_over_x_ratio = 1. # no change to the heightmap
|
|
505
|
+
# logger.warning('db not found, assuming scaling factor is 1, which is very unlikely.')
|
|
506
|
+
if voxel_z_over_x_ratio != 1.:
|
|
507
|
+
height_map = height_map * voxel_z_over_x_ratio
|
|
508
|
+
if __DEBUG__:
|
|
509
|
+
print(
|
|
510
|
+
'applying aspect ratio ' + str(voxel_z_over_x_ratio) + ' to the height map of file ' + str(
|
|
511
|
+
file_or_list))
|
|
512
|
+
logger.info(
|
|
513
|
+
'applying aspect ratio ' + str(voxel_z_over_x_ratio) + ' to the height map of file ' + str(
|
|
514
|
+
file_or_list))
|
|
515
|
+
except:
|
|
516
|
+
# logger.error(
|
|
517
|
+
# 'height map' + str(height_map_file) + ' could not be loaded, 3D measurements are not possible')
|
|
518
|
+
traceback.print_exc()
|
|
519
|
+
pass
|
|
520
|
+
if height_map is None:
|
|
521
|
+
if __DEBUG__:
|
|
522
|
+
print('height map' + str(height_map_file) + ' file is missing, 3D measurements are not possible')
|
|
523
|
+
logger.error('height map' + str(height_map_file) + ' file is missing, 3D measurements are not possible') # log that there is a missing height map and that not much can be done
|
|
524
|
+
|
|
525
|
+
|
|
526
|
+
if __DEBUG__:
|
|
527
|
+
print('debug #4')
|
|
528
|
+
# height_map = None #Img('/E/Sample_images/sample_images_PA/mini/focused_Series012.png')[..., 1]
|
|
529
|
+
# height_map = Img('/E/Sample_images/sample_images_PA/mini/focused_Series012.png')[..., 0] # another good test because all is 0 there --> marche car aire est proche de l'aire 2D par contre pr handcorrection ça marche pas car tres different de l'aire 2D --> see why and how to fix it
|
|
530
|
+
# height_map = Img('/E/Sample_images/sample_images_PA/mini/focused_Series012/handCorrection.png')[..., 0] # good for a test as all heights are the same... --> in fact that makes sense since some heigts are 0 and some are 255 since the centroid of the polygon is always 0
|
|
531
|
+
|
|
532
|
+
# all seems to work now
|
|
533
|
+
lab_cells = label(cells, connectivity=1, background=255)
|
|
534
|
+
|
|
535
|
+
if __DEBUG__:
|
|
536
|
+
print('debug #4a')
|
|
537
|
+
if TA_path is not None:
|
|
538
|
+
Img(lab_cells, dimensions='hw').save(os.path.join(TA_path,
|
|
539
|
+
'cells.tif')) # Pretty much the same as cell_identity.tif in TA --> cool and more useful in a way!!!
|
|
540
|
+
else:
|
|
541
|
+
# plt.imshow(cells)
|
|
542
|
+
# plt.show()
|
|
543
|
+
pass
|
|
544
|
+
if __DEBUG__:
|
|
545
|
+
print('debug #4b')
|
|
546
|
+
#
|
|
547
|
+
# vertices = detect_vertices_and_bonds(lab_cells, boundary_color=0)
|
|
548
|
+
vertices = detect_vertices_and_bonds(lab_cells, boundary_color=0)
|
|
549
|
+
|
|
550
|
+
if __DEBUG__:
|
|
551
|
+
print('debug #4c')
|
|
552
|
+
|
|
553
|
+
width = vertices.shape[1]
|
|
554
|
+
height = vertices.shape[0]
|
|
555
|
+
|
|
556
|
+
|
|
557
|
+
if __DEBUG__:
|
|
558
|
+
print('debug #4d')
|
|
559
|
+
# ok whereas the other one gives a bug
|
|
560
|
+
|
|
561
|
+
# c'est ce code qui donne une seg fault
|
|
562
|
+
try:
|
|
563
|
+
border_cells = get_border_cells(lab_cells, bg_color=0)
|
|
564
|
+
except:
|
|
565
|
+
traceback.print_exc()
|
|
566
|
+
logger.error('Could not detect border cells')
|
|
567
|
+
border_cells=[]
|
|
568
|
+
# border_cells=[]
|
|
569
|
+
# border_cells_plus_one = get_border_cells_plus_one(get_cells_and_their_neighbors_from_image(lab_cells, vertices=np.asarray(np.where(vertices==255))), border_cells, remove_border_cells=True)
|
|
570
|
+
|
|
571
|
+
if __DEBUG__:
|
|
572
|
+
print('debug #4e')
|
|
573
|
+
|
|
574
|
+
# this is super slow --> 4 secs --> that really sucks --> but in fact the overhead is just for the first image then it's faster --> that probably would work
|
|
575
|
+
# works as nicely with pixels of the boundary
|
|
576
|
+
# border_cells_plus_one = get_border_cells_plus_one(get_cells_and_their_neighbors_from_image(lab_cells, vertices=np.stack(np.where(vertices != 0), axis=1),bg_color=0), border_cells, remove_border_cells=True)
|
|
577
|
+
border_cells_plus_one = get_border_cells_plus_one(
|
|
578
|
+
get_cells_and_their_neighbors_from_image(lab_cells, vertices=np.stack(np.where(lab_cells == 0), axis=1),
|
|
579
|
+
bg_color=0), border_cells,
|
|
580
|
+
remove_border_cells=True) # this is as fast and detects nicely the cells having no vertices --> maybe I should by the way rather use that for cell neighborhood --> TODO
|
|
581
|
+
|
|
582
|
+
|
|
583
|
+
if __DEBUG__:
|
|
584
|
+
print('debug #4f')
|
|
585
|
+
# exclude border cells plus one for now and add it later --> need a bit of recoding and no big deal!!!
|
|
586
|
+
|
|
587
|
+
# print(np.nonzero(vertices))
|
|
588
|
+
|
|
589
|
+
border_vertices = []
|
|
590
|
+
border_vertices_plus_one = []
|
|
591
|
+
|
|
592
|
+
if __DEBUG__:
|
|
593
|
+
print('debug #5')
|
|
594
|
+
|
|
595
|
+
# this creates a local ID for vertices (same as a label for vertices) # may be numbaised to gain speed if needed
|
|
596
|
+
non_zero_y, non_zero_x = np.nonzero(vertices)
|
|
597
|
+
locally_labeled_vertices = np.zeros_like(vertices, dtype=lab_cells.dtype)
|
|
598
|
+
for iii in range(len(non_zero_x)):
|
|
599
|
+
locally_labeled_vertices[non_zero_y[iii], non_zero_x[iii]] = iii + 1
|
|
600
|
+
# also we add it to the database
|
|
601
|
+
vertices_2D['local_ID'].append(iii + 1)
|
|
602
|
+
# print('non_zero_x[iii]',non_zero_x[iii])
|
|
603
|
+
x = non_zero_x[iii]
|
|
604
|
+
y = non_zero_y[iii]
|
|
605
|
+
vertices_2D['y'].append(y)
|
|
606
|
+
vertices_2D['x'].append(x)
|
|
607
|
+
if x == 0 or y == 0 or x == width - 1 or y == height - 1:
|
|
608
|
+
vertices_2D['is_border'].append(1)
|
|
609
|
+
border_vertices.append(iii + 1)
|
|
610
|
+
else:
|
|
611
|
+
vertices_2D['is_border'].append(0)
|
|
612
|
+
if x == 1 or y == 1 or x == width - 2 or y == height - 2:
|
|
613
|
+
vertices_2D['is_border_plus_one'].append(1)
|
|
614
|
+
border_vertices_plus_one.append(iii + 1)
|
|
615
|
+
else:
|
|
616
|
+
vertices_2D['is_border_plus_one'].append(0)
|
|
617
|
+
|
|
618
|
+
if __DEBUG__:
|
|
619
|
+
print('debug #6')
|
|
620
|
+
|
|
621
|
+
if TA_path is not None:
|
|
622
|
+
Img(locally_labeled_vertices, dimensions='hw').save(
|
|
623
|
+
os.path.join(TA_path, 'vertices.tif')) # similar but not identical to TA vertices.tif file
|
|
624
|
+
else:
|
|
625
|
+
# plt.imshow(locally_labeled_vertices)
|
|
626
|
+
# plt.show()
|
|
627
|
+
pass
|
|
628
|
+
|
|
629
|
+
# plt.imshow(localy_labeled_vertices)
|
|
630
|
+
# plt.show()
|
|
631
|
+
|
|
632
|
+
# need color all vertices
|
|
633
|
+
# vertices_coords = np.nonzero(vertices)
|
|
634
|
+
|
|
635
|
+
# plt.imshow(vertices)
|
|
636
|
+
# plt.show()
|
|
637
|
+
# should I label the vertices ??? --> maybe because that could be useful but ok maybe for now
|
|
638
|
+
|
|
639
|
+
# bonds = np.copy(lab_cells)
|
|
640
|
+
bonds = cantor_color_bonds(lab_cells, vertices, boundary_color=0) #
|
|
641
|
+
bonds[vertices == 255] = 0 # really needs be done --> do a meta function that does all
|
|
642
|
+
# in fact real bonds need remove vertices
|
|
643
|
+
|
|
644
|
+
lab_bonds = label(bonds, connectivity=2,
|
|
645
|
+
background=0) # nb I SHOULD NOT RELABEL THEM BECAUSE I MAY CREATE ERRORS BY DOING SO
|
|
646
|
+
# lab_bonds = np.copy(bonds)
|
|
647
|
+
|
|
648
|
+
if TA_path is not None:
|
|
649
|
+
# print(lab_bonds.dtype)
|
|
650
|
+
Img(lab_bonds, dimensions='hw').save(
|
|
651
|
+
os.path.join(TA_path, 'bonds.tif')) # pretty much the same as boundaryPlotter.tif in TA!!!
|
|
652
|
+
# print('--->'*5,lab_bonds.dtype)
|
|
653
|
+
else:
|
|
654
|
+
# plt.imshow(lab_bonds)
|
|
655
|
+
# plt.show()
|
|
656
|
+
pass
|
|
657
|
+
|
|
658
|
+
rps_bonds = regionprops(lab_bonds)
|
|
659
|
+
|
|
660
|
+
|
|
661
|
+
if __DEBUG__:
|
|
662
|
+
print('debug #7')
|
|
663
|
+
# try to add vertices to bonds but in fact does not work well --> need an alternative method --> should be easy to do I guess !! --> TODO or I do have a mistake
|
|
664
|
+
# or get feret points and find vertex for it or take points with 7 false around them and get the corresponding vertex on the image --> maybe a good idea
|
|
665
|
+
# take first and last and if not good scan all points to find real edges
|
|
666
|
+
|
|
667
|
+
# then find pairs of vertices --> not hard --> gives new bonds
|
|
668
|
+
# get coord in real image
|
|
669
|
+
|
|
670
|
+
# can I get the vertices of every bond
|
|
671
|
+
# need specify an ID per bond and increment for super tiny ones --> would be the local ID and can make it that there is table that can be joined that connects local and global ids --> easy todo I think
|
|
672
|
+
|
|
673
|
+
# if any error occurs --> skip the whole stuff
|
|
674
|
+
|
|
675
|
+
# if anything goes wrong with the bond skip the whole line from saving --> can I do that --> not really except if all is saved at the same time in the very end --> I could try that
|
|
676
|
+
|
|
677
|
+
max_bond_id = 0
|
|
678
|
+
for bond in rps_bonds:
|
|
679
|
+
|
|
680
|
+
if early_stop.stop == True:
|
|
681
|
+
# print('early stop')
|
|
682
|
+
return
|
|
683
|
+
# print('False perimeter', bond.perimeter)
|
|
684
|
+
# --> ok
|
|
685
|
+
|
|
686
|
+
bbox = bond.bbox
|
|
687
|
+
|
|
688
|
+
# y_shift_to_transfrom_local_coords_to_global_coords = 0
|
|
689
|
+
# x_shift_to_transfrom_local_coords_to_global_coords = 0
|
|
690
|
+
|
|
691
|
+
if bbox[0] == 0 or bbox[0] == lab_bonds.shape[0] - 1:
|
|
692
|
+
|
|
693
|
+
x_shift_to_transfrom_local_coords_to_global_coords = bbox[1] - 1
|
|
694
|
+
y_shift_to_transfrom_local_coords_to_global_coords = bbox[0]
|
|
695
|
+
# print(bbox[0],bbox)
|
|
696
|
+
|
|
697
|
+
img = np.zeros((bond.image.shape[0], bond.image.shape[1] + 2), dtype=bond.image.dtype)
|
|
698
|
+
img[:, 1:-1] = bond.image
|
|
699
|
+
# print(bond.image.shape, img.shape)
|
|
700
|
+
# if bbox[0]==0:
|
|
701
|
+
img[0, 0] = True
|
|
702
|
+
img[0, img.shape[1] - 1] = True
|
|
703
|
+
# else:
|
|
704
|
+
# img[img.shape[0]-1, 0] = True
|
|
705
|
+
# img[img.shape[0]-1, img.shape[1]-1] = True
|
|
706
|
+
# plt.imshow(img.astype(np.uint8)*255, cmap='gray', vmin=0)
|
|
707
|
+
# plt.show()
|
|
708
|
+
# if img.shape[0]!=1:
|
|
709
|
+
# plt.imshow(img.astype(np.uint8) * 255, cmap='gray', vmin=0)
|
|
710
|
+
# plt.show()
|
|
711
|
+
elif bbox[1] == 0 or bbox[1] == lab_bonds.shape[1] - 1:
|
|
712
|
+
x_shift_to_transfrom_local_coords_to_global_coords = bbox[1]
|
|
713
|
+
y_shift_to_transfrom_local_coords_to_global_coords = bbox[0] - 1
|
|
714
|
+
# print(bbox[0],bbox)
|
|
715
|
+
img = np.zeros((bond.image.shape[0] + 2, bond.image.shape[1]), dtype=bond.image.dtype)
|
|
716
|
+
img[1:-1, :] = bond.image
|
|
717
|
+
# print(bond.image.shape, img.shape)
|
|
718
|
+
# if bbox[1] == 0:
|
|
719
|
+
img[0, 0] = True
|
|
720
|
+
img[img.shape[0] - 1, 0] = True
|
|
721
|
+
# else:
|
|
722
|
+
# img[img.shape[0] - 1, 0] = True
|
|
723
|
+
# img[img.shape[0] - 1, img.shape[0] - 1] = True
|
|
724
|
+
# plt.imshow(img.astype(np.uint8)*255, cmap='gray', vmin=0)
|
|
725
|
+
# plt.show()
|
|
726
|
+
# if img.shape[1] != 1:
|
|
727
|
+
# plt.imshow(img.astype(np.uint8) * 255, cmap='gray', vmin=0)
|
|
728
|
+
# plt.show()
|
|
729
|
+
else:
|
|
730
|
+
x_shift_to_transfrom_local_coords_to_global_coords = bbox[1] - 1
|
|
731
|
+
y_shift_to_transfrom_local_coords_to_global_coords = bbox[0] - 1
|
|
732
|
+
img = np.pad(bond.image, pad_width=1, mode='constant', constant_values=False)
|
|
733
|
+
# how can I get these coords
|
|
734
|
+
|
|
735
|
+
# can use those coords of vertices to add vertices associated to bonds into a db --> I need correct their y and x but ok
|
|
736
|
+
# coords = np.nonzero(vertices[bbox[0] - 1:bbox[2] + 1, bbox[1] - 1: bbox[
|
|
737
|
+
# 3] + 1] == 255) # TODO DO THIS FOR ALL CHANNELS --> recover vertices here --> clone this for all --> TODO
|
|
738
|
+
|
|
739
|
+
# print('coords vertices', coords) # --> gives me the coords of the vertices
|
|
740
|
+
# print('zipped coords', np.c_[coords[0], coords[1]]) # this is how to zip numpy arrays -> in fact simpler than doing too complicated things --> VRAIMENT COOL
|
|
741
|
+
# NB I could also use np.dstack((coords[0], coords[1]))
|
|
742
|
+
|
|
743
|
+
# TODO add things to the DB if necessary
|
|
744
|
+
# in tracks and in seg --> make sure to add a boundary around the image --> do this as an option -> but in fact really useful to do
|
|
745
|
+
|
|
746
|
+
# --> can associate local bond id to that
|
|
747
|
+
img[vertices[bbox[0] - 1:bbox[2] + 1, bbox[1] - 1: bbox[
|
|
748
|
+
3] + 1] == 255] = True # add vertices to the mask because they are not captured by the dilation
|
|
749
|
+
|
|
750
|
+
# print('global coords', x_shift_to_transfrom_local_coords_to_global_coords, y_shift_to_transfrom_local_coords_to_global_coords)
|
|
751
|
+
# associate a bond to a local id
|
|
752
|
+
# very good idea in fact
|
|
753
|
+
# also measure intensity
|
|
754
|
+
|
|
755
|
+
# create bonds and find a way to transform local coords into global ones -> must not be hard --> can compute intensity for several channels if needed
|
|
756
|
+
# store as NA depending on the channel
|
|
757
|
+
# not bad and much better than before in fact
|
|
758
|
+
|
|
759
|
+
# if negative values --> need a double fix so that same size --> see how to do that but probably not so hard
|
|
760
|
+
# img[vertices[bbox[0] :bbox[2] + 2, bbox[1] : bbox[3] + 2] == 255] = True # add vertices to the mask because they are not captured by the dilation
|
|
761
|
+
|
|
762
|
+
# img[0][0]=True
|
|
763
|
+
# first and last pixel
|
|
764
|
+
# first_point = [bond.coords[0][0],bond.coords[0][1]]
|
|
765
|
+
# last_point = [bond.coords[len(bond.coords[0])][0],bond.coords[len(bond.coords[0])][1]]
|
|
766
|
+
#
|
|
767
|
+
# print(first_point, last_point)
|
|
768
|
+
|
|
769
|
+
# plt.imshow(img)
|
|
770
|
+
# plt.show()
|
|
771
|
+
|
|
772
|
+
# if __DEBUG__:
|
|
773
|
+
# print('debug #8')
|
|
774
|
+
|
|
775
|
+
lab_perim = label(img, connectivity=2)
|
|
776
|
+
reg = regionprops(lab_perim)
|
|
777
|
+
idx = 0
|
|
778
|
+
if len(reg) != 1:
|
|
779
|
+
# print('error too many things for bonds')
|
|
780
|
+
# plt.imshow(lab_perim)
|
|
781
|
+
# plt.show()
|
|
782
|
+
|
|
783
|
+
max_area = 0
|
|
784
|
+
for ppp, perim in enumerate(reg):
|
|
785
|
+
if perim.area > max_area:
|
|
786
|
+
max_area = perim.area
|
|
787
|
+
idx = ppp
|
|
788
|
+
|
|
789
|
+
# print(idx, )
|
|
790
|
+
# again need take biggest
|
|
791
|
+
|
|
792
|
+
# print('fixed 000', idx)
|
|
793
|
+
|
|
794
|
+
# make it measure intensity for the different channels of the image
|
|
795
|
+
# do quantifs for all channels --> TODO
|
|
796
|
+
|
|
797
|
+
# code seems ok but maybe I need to split it
|
|
798
|
+
# see how to do
|
|
799
|
+
# could check if it is a real bond for packing in fact --> TODO
|
|
800
|
+
|
|
801
|
+
# print('real_perimeter bond', reg[idx].perimeter,reg[idx].area) # the latter is pixel count reg[idx].perimeter_crofton,
|
|
802
|
+
|
|
803
|
+
# juts plot it to be sure no error of vertices --> otherwise needs a fix
|
|
804
|
+
|
|
805
|
+
# could do that for all the channels
|
|
806
|
+
|
|
807
|
+
# could also do that before adding vertices in fact --> TODO
|
|
808
|
+
|
|
809
|
+
vertices_tmp = locally_labeled_vertices[
|
|
810
|
+
reg[idx].coords[:, 0] + y_shift_to_transfrom_local_coords_to_global_coords,
|
|
811
|
+
reg[idx].coords[:, 1] + x_shift_to_transfrom_local_coords_to_global_coords]
|
|
812
|
+
vertices_indices = np.nonzero(vertices_tmp)
|
|
813
|
+
|
|
814
|
+
# get vertices in the region...
|
|
815
|
+
|
|
816
|
+
# print('vertices_indices',vertices_indices)
|
|
817
|
+
vertices_ids = vertices_tmp[vertices_indices]
|
|
818
|
+
del vertices_tmp
|
|
819
|
+
vertices_indices = vertices_indices[0]
|
|
820
|
+
vertices_ids = vertices_ids.tolist()
|
|
821
|
+
vertices_indices = vertices_indices.tolist()
|
|
822
|
+
|
|
823
|
+
# print('vertices_ids', vertices_ids, vertices_indices)
|
|
824
|
+
|
|
825
|
+
# can this be a bug --> I guess yes --> need a fix then --> maybe take the two closest bonds and remove one ???
|
|
826
|
+
|
|
827
|
+
# VERY DIRTY FIX FOR CASE WHERE TOO MANY VERTICES ARE THERE --> SEE IF THERE IS NO SIMPLER SOLUTION WHEN ADDING THE VERTICES TO ONLY GET THE RIGHT ONES
|
|
828
|
+
|
|
829
|
+
# if __DEBUG__:
|
|
830
|
+
# print('debug #9')
|
|
831
|
+
# FORCES ME TO REPEAT A LOT OF CODE --> NOT A GOOD IDEA!!!
|
|
832
|
+
if len(vertices_ids) > 2:
|
|
833
|
+
try:
|
|
834
|
+
# logger.error( 'error: wrong number of vertices --> please report this to baigouy@gmail.com' + str(vertices_ids))
|
|
835
|
+
|
|
836
|
+
# for debug KEEP
|
|
837
|
+
# vx_0 = (
|
|
838
|
+
# reg[idx].coords[vertices_indices[0], 0] ,
|
|
839
|
+
# reg[idx].coords[vertices_indices[0], 1] )
|
|
840
|
+
# vx_1 = (reg[idx].coords[vertices_indices[1], 0] ,
|
|
841
|
+
# reg[idx].coords[vertices_indices[1], 1] )
|
|
842
|
+
# vx_2 = (reg[idx].coords[vertices_indices[2], 0] ,
|
|
843
|
+
# reg[idx].coords[vertices_indices[2], 1] )
|
|
844
|
+
#
|
|
845
|
+
# print(vx_0,vx_1, vx_2)
|
|
846
|
+
# lab_perim[vx_0[0], vx_0[1]]+=1
|
|
847
|
+
# lab_perim[vx_1[0], vx_1[1]]+=1
|
|
848
|
+
# lab_perim[vx_2[0], vx_2[1]]+=1
|
|
849
|
+
|
|
850
|
+
# In fact need take the last vx encounter on the left and the last starting from the right
|
|
851
|
+
tmp = list(zip(reg[idx].coords[:, 0], reg[idx].coords[:, 1]))
|
|
852
|
+
vx_coords = [(reg[idx].coords[indx, 0], reg[idx].coords[indx, 1]) for indx in vertices_indices]
|
|
853
|
+
|
|
854
|
+
tmp2 = list(set(tmp) - set(vx_coords))
|
|
855
|
+
from scipy.spatial import distance
|
|
856
|
+
|
|
857
|
+
C = distance.pdist(vx_coords)
|
|
858
|
+
|
|
859
|
+
valid_idx = np.where(C > math.sqrt(2))[0]
|
|
860
|
+
out = valid_idx[C[valid_idx].argmin()]
|
|
861
|
+
|
|
862
|
+
coords = np.argwhere(squareform(C) == C[out])[0]
|
|
863
|
+
|
|
864
|
+
vx_0 = vx_coords[coords[0]]
|
|
865
|
+
vx_1 = vx_coords[coords[1]]
|
|
866
|
+
|
|
867
|
+
# print('vx_0, vx_1', vx_0, vx_1)
|
|
868
|
+
|
|
869
|
+
group1 = []
|
|
870
|
+
group2 = []
|
|
871
|
+
|
|
872
|
+
for coord in vx_coords:
|
|
873
|
+
if distance_between_points(vx_0, coord) <= math.sqrt(2):
|
|
874
|
+
group1.append(coord)
|
|
875
|
+
if distance_between_points(vx_1, coord) <= math.sqrt(2):
|
|
876
|
+
group2.append(coord)
|
|
877
|
+
|
|
878
|
+
# print('groups', group1, group2)
|
|
879
|
+
|
|
880
|
+
if len(group1) == 1:
|
|
881
|
+
vx_0 = group1[0]
|
|
882
|
+
else:
|
|
883
|
+
# find closest vx to non vx pixels and that will always be my two real vertices!
|
|
884
|
+
min_dist = 1000
|
|
885
|
+
closest = group1[0]
|
|
886
|
+
for coord in group1:
|
|
887
|
+
dist = distance.cdist(tmp2, [coord]).min()
|
|
888
|
+
if dist < min_dist:
|
|
889
|
+
min_dist = dist
|
|
890
|
+
closest = coord
|
|
891
|
+
if dist == 1:
|
|
892
|
+
break
|
|
893
|
+
vx_0 = closest
|
|
894
|
+
|
|
895
|
+
if len(group2) == 1:
|
|
896
|
+
vx_1 = group2[0]
|
|
897
|
+
else:
|
|
898
|
+
# find closest vx to non vx pixels and that will always be my two real vertices!
|
|
899
|
+
min_dist = 1000
|
|
900
|
+
closest = group2[0]
|
|
901
|
+
for coord in group2:
|
|
902
|
+
dist = distance.cdist(tmp2, [coord]).min()
|
|
903
|
+
if dist < min_dist:
|
|
904
|
+
min_dist = dist
|
|
905
|
+
closest = coord
|
|
906
|
+
if dist == 1:
|
|
907
|
+
break
|
|
908
|
+
vx_1 = closest
|
|
909
|
+
|
|
910
|
+
# this is now always ok --> I have finally my code !!!
|
|
911
|
+
# need get the indices and finalize the stuff
|
|
912
|
+
|
|
913
|
+
# idx1 = tmp.index(vx_0)
|
|
914
|
+
# idx2 = tmp.index(vx_1)
|
|
915
|
+
|
|
916
|
+
# print('idx1, idx2', idx1, idx2)
|
|
917
|
+
|
|
918
|
+
# print('pre', vertices_indices, vertices_ids)
|
|
919
|
+
|
|
920
|
+
# vertices_ids = [vertices_ids[vertices_indices.index(idx1)], vertices_ids[vertices_indices.index(idx2)]]
|
|
921
|
+
|
|
922
|
+
# vertices_indices = [idx1, idx2]
|
|
923
|
+
# print('corrected', vertices_ids, vertices_indices)
|
|
924
|
+
|
|
925
|
+
# for debug --> keep
|
|
926
|
+
# lab_perim[vx_0[0], vx_0[1]] += 1
|
|
927
|
+
# lab_perim[vx_1[0], vx_1[1]] += 1
|
|
928
|
+
|
|
929
|
+
# plt.imshow(lab_perim)
|
|
930
|
+
# plt.show()
|
|
931
|
+
|
|
932
|
+
# update mask and reg with the removed vertices so that all measures and alike are correct --> TOO BAD I HAVE TO DUPLICTAE SO MUCH CODE (SEE ALL THE LINES BELOW) BUT OK FOR NOW
|
|
933
|
+
for vx in vx_coords:
|
|
934
|
+
img[vx[0], vx[1]] = False
|
|
935
|
+
|
|
936
|
+
img[vx_0[0], vx_0[1]] = True
|
|
937
|
+
img[vx_1[0], vx_1[1]] = True
|
|
938
|
+
lab_perim = label(img, connectivity=2)
|
|
939
|
+
reg = regionprops(lab_perim)
|
|
940
|
+
idx = 0
|
|
941
|
+
if len(reg) != 1:
|
|
942
|
+
# print('error too many things for bonds')
|
|
943
|
+
# plt.imshow(lab_perim)
|
|
944
|
+
# plt.show()
|
|
945
|
+
|
|
946
|
+
max_area = 0
|
|
947
|
+
for ppp, perim in enumerate(reg):
|
|
948
|
+
if perim.area > max_area:
|
|
949
|
+
max_area = perim.area
|
|
950
|
+
idx = ppp
|
|
951
|
+
|
|
952
|
+
vertices_tmp = locally_labeled_vertices[
|
|
953
|
+
reg[idx].coords[:, 0] + y_shift_to_transfrom_local_coords_to_global_coords,
|
|
954
|
+
reg[idx].coords[:, 1] + x_shift_to_transfrom_local_coords_to_global_coords]
|
|
955
|
+
vertices_indices = np.nonzero(vertices_tmp)
|
|
956
|
+
|
|
957
|
+
# get vertices in the region...
|
|
958
|
+
|
|
959
|
+
# print('vertices_indices',vertices_indices)
|
|
960
|
+
vertices_ids = vertices_tmp[vertices_indices]
|
|
961
|
+
del vertices_tmp
|
|
962
|
+
vertices_indices = vertices_indices[0]
|
|
963
|
+
vertices_ids = vertices_ids.tolist()
|
|
964
|
+
vertices_indices = vertices_indices.tolist()
|
|
965
|
+
|
|
966
|
+
# plt.imshow(lab_perim)
|
|
967
|
+
# plt.show()
|
|
968
|
+
except:
|
|
969
|
+
traceback.print_exc()
|
|
970
|
+
if __DEBUG__:
|
|
971
|
+
print('error correcting the number of vertices of the bond --> please report this to benoit.aigouy@gmail.com')
|
|
972
|
+
logger.error(
|
|
973
|
+
'error correcting the number of vertices of the bond --> please report this to benoit.aigouy@gmail.com')
|
|
974
|
+
|
|
975
|
+
# TODO see how to handle that because this is super frequent in fact !!!! but not easy to deal with...
|
|
976
|
+
|
|
977
|
+
# if __DEBUG__:
|
|
978
|
+
# print('debug #10')
|
|
979
|
+
# TODO DO THIS FOR ALL CHANNELS
|
|
980
|
+
# maybe do that vertices included or not ??? MAYBE
|
|
981
|
+
|
|
982
|
+
# print(type(reg), type(reg[idx]))
|
|
983
|
+
|
|
984
|
+
sum_bd_intensity, avg_bd_intensity = get_sum_and_avg_intensity(original_image, reg, idx,
|
|
985
|
+
y_shift_to_transfrom_local_coords_to_global_coords,
|
|
986
|
+
x_shift_to_transfrom_local_coords_to_global_coords)
|
|
987
|
+
|
|
988
|
+
# nb the vertices are the two points of the region coords to be white in the parent image with local transform --> how cna I find them
|
|
989
|
+
|
|
990
|
+
# print('reg[idx]',reg[idx])
|
|
991
|
+
# if not vertices_ids:
|
|
992
|
+
# plt.imshow(lab_perim)
|
|
993
|
+
# plt.show()
|
|
994
|
+
|
|
995
|
+
# in some case the vertices_indices can be empty --> is that normal or a bug ??? --> probably a bug that needs be fixed --> this is because vertices ids is also empty --> how can I fix that wand why does this happens
|
|
996
|
+
# print('neo vertices', vertices_indices) # this gives me the indices of the vertices of the bonds --> see how I can associate them with a cell at some point maybe if necessary
|
|
997
|
+
|
|
998
|
+
# KEEP nb a cell can have 0 vertices --> indeed a floating cell embedded in another would have 0 vertex --> shall I give it a nb of vertices of 1 or 0??? --> maybe smart to set its vertex id to None/Null
|
|
999
|
+
|
|
1000
|
+
# In case the bond has no vertices do as follows
|
|
1001
|
+
first_vx = None
|
|
1002
|
+
second_vertex = None
|
|
1003
|
+
bd_orientation = None
|
|
1004
|
+
|
|
1005
|
+
if vertices_indices:
|
|
1006
|
+
first_vertex = (
|
|
1007
|
+
reg[idx].coords[vertices_indices[0], 0] + y_shift_to_transfrom_local_coords_to_global_coords,
|
|
1008
|
+
reg[idx].coords[vertices_indices[0], 1] + x_shift_to_transfrom_local_coords_to_global_coords)
|
|
1009
|
+
second_vertex = (
|
|
1010
|
+
reg[idx].coords[vertices_indices[-1], 0] + y_shift_to_transfrom_local_coords_to_global_coords,
|
|
1011
|
+
reg[idx].coords[vertices_indices[-1], 1] + x_shift_to_transfrom_local_coords_to_global_coords)
|
|
1012
|
+
bd_orientation = get_orientation(first_vertex, second_vertex)
|
|
1013
|
+
|
|
1014
|
+
# TODO action required if more than two vertices --> take the two furthest appart or the first and last --> MAYBE WILL NEED A CLEAN/SMART FIX SOME DAY
|
|
1015
|
+
# print('first_vertex, second_vertex',first_vertex, second_vertex)
|
|
1016
|
+
first_vx = vertices_ids[0]
|
|
1017
|
+
second_vertex = vertices_ids[-1]
|
|
1018
|
+
|
|
1019
|
+
# print('TODO sum_bd_intensity,avg_bd_intensity',sum_bd_intensity,avg_bd_intensity)
|
|
1020
|
+
|
|
1021
|
+
# keep for debug --> if the original mask is passed max and min should always be 255 --> the mask color --> seems to work perfectly --> and also avg should always be 255, if less --> bug somewhere --> needs a fix --> TODO
|
|
1022
|
+
# could do the same with the cells in fact
|
|
1023
|
+
# also need fix local centoid wit that in fact i can probably still take the centroid
|
|
1024
|
+
# print('max, min', original_image[reg[idx].coords[:, 0]+y_shift_to_transfrom_local_coords_to_global_coords, reg[idx].coords[:, 1]+x_shift_to_transfrom_local_coords_to_global_coords].max(), original_image[reg[idx].coords[:, 0]+y_shift_to_transfrom_local_coords_to_global_coords, reg[idx].coords[:, 1]+x_shift_to_transfrom_local_coords_to_global_coords].min()) # alw
|
|
1025
|
+
|
|
1026
|
+
# required prior to quantification of 3D length of bonds
|
|
1027
|
+
|
|
1028
|
+
# TODO NEED PATCH THE COORDS THERE IN FACT
|
|
1029
|
+
# print('sorted_bond', sorted_bond)
|
|
1030
|
+
|
|
1031
|
+
x_shift_to_transfrom_local_coords_to_global_coords = bbox[1] - 1 # why -1 --> should in fact be the right stuff
|
|
1032
|
+
y_shift_to_transfrom_local_coords_to_global_coords = bbox[0] - 1
|
|
1033
|
+
|
|
1034
|
+
# if __DEBUG__:
|
|
1035
|
+
# print('debug #11')
|
|
1036
|
+
|
|
1037
|
+
if measure_3D and height_map is not None:
|
|
1038
|
+
sorted_bond = pavlidis(reg[idx], closed_contour=False)
|
|
1039
|
+
sorted_bond = [
|
|
1040
|
+
[y + y_shift_to_transfrom_local_coords_to_global_coords,
|
|
1041
|
+
x + x_shift_to_transfrom_local_coords_to_global_coords]
|
|
1042
|
+
for y, x in sorted_bond]
|
|
1043
|
+
|
|
1044
|
+
bd_length3D = perimeter_3D(sorted_bond, heightmap=height_map, points_are_sorted=True,
|
|
1045
|
+
is_closed_contour=False)
|
|
1046
|
+
|
|
1047
|
+
# print('length3D', bd_length3D)
|
|
1048
|
+
|
|
1049
|
+
# we save all the data in the very end so that if anything goes wrong no data is added at all
|
|
1050
|
+
max_bond_id = max(max_bond_id, bond.label)
|
|
1051
|
+
bonds_2D['local_ID'].append(bond.label)
|
|
1052
|
+
bonds_3D['local_ID'].append(bond.label)
|
|
1053
|
+
bonds_2D['length'].append(reg[idx].perimeter)
|
|
1054
|
+
bonds_2D['pixel_count'].append(reg[idx].area)
|
|
1055
|
+
local_bond_ID_and_px_count[bond.label] = reg[idx].area
|
|
1056
|
+
|
|
1057
|
+
bonds_2D['first_pixel_x'].append(bond.coords[0][0])
|
|
1058
|
+
bonds_2D['first_pixel_y'].append(bond.coords[0][1])
|
|
1059
|
+
|
|
1060
|
+
# bug because some bonds lie at the margin and their neighb should not be found like that --> in fact that would still work I guess
|
|
1061
|
+
# if nothing --> border bond ???? --> think about it
|
|
1062
|
+
# cells_around_bond = set(lab_cells[bond.coords[0][0] - 1:bond.coords[0][0] + 2, bond.coords[0][1] - 1:bond.coords[0][1] + 2].ravel().tolist())# THIS CREATES A BUG WITH NEGATIVE SLICES BUT NO CLUE WHY --> IS THAT A SECURITY ANYWAY NOT WHAT I WANT !!!
|
|
1063
|
+
cells_around_bond = set(
|
|
1064
|
+
neighbors8(bond.coords[0], lab_cells)) # nb this is another way of detecting border cells!!!
|
|
1065
|
+
if 0 in cells_around_bond:
|
|
1066
|
+
cells_around_bond.remove(0)
|
|
1067
|
+
cells_around_bond = list(cells_around_bond)
|
|
1068
|
+
# print('cells_around_bond',cells_around_bond)
|
|
1069
|
+
|
|
1070
|
+
# --> indeed border bonds ???
|
|
1071
|
+
|
|
1072
|
+
# border bonds have just one neighbor --> easy to spot them
|
|
1073
|
+
# --> in fact should still be one
|
|
1074
|
+
# if len(cells_around_bond)==0:
|
|
1075
|
+
#
|
|
1076
|
+
#
|
|
1077
|
+
#
|
|
1078
|
+
# print('bug')
|
|
1079
|
+
# print(bond.coords[0][0], bond.coords[0][1])
|
|
1080
|
+
# # somehow there is a bug here
|
|
1081
|
+
# # print(lab_cells[int(bond.coords[0][0] - 1):int(bond.coords[0][0] + 2), int(bond.coords[0][1] - 1):int(bond.coords[0][1] + 2)], bond.coords[0][0] - 1,bond.coords[0][0] + 2, bond.coords[0][1] - 1,bond.coords[0][1] + 2)
|
|
1082
|
+
# # print(neighbors8(bond.coords[0], lab_cells))
|
|
1083
|
+
# plt.imshow(lab_cells)
|
|
1084
|
+
# plt.show()
|
|
1085
|
+
|
|
1086
|
+
# bonds_2D['vx_1_y'].append(first_vertex[0])
|
|
1087
|
+
# bonds_2D['vx_1_x'].append(first_vertex[1])
|
|
1088
|
+
# bonds_2D['vx_2_y'].append(second_vertex[0])
|
|
1089
|
+
# bonds_2D['vx_2_x'].append(second_vertex[1])
|
|
1090
|
+
|
|
1091
|
+
bonds_2D['vx_1'].append(first_vx)
|
|
1092
|
+
bonds_2D['vx_2'].append(second_vertex)
|
|
1093
|
+
|
|
1094
|
+
# how is it possible that some bonds have 0 id around them --> need think abount it
|
|
1095
|
+
if cells_around_bond:
|
|
1096
|
+
bonds_2D['cell_id1_around_bond'].append(cells_around_bond[0])
|
|
1097
|
+
bonds_2D['cell_id2_around_bond'].append(cells_around_bond[-1])
|
|
1098
|
+
else:
|
|
1099
|
+
bonds_2D['cell_id1_around_bond'].append(None)
|
|
1100
|
+
bonds_2D['cell_id2_around_bond'].append(None)
|
|
1101
|
+
is_border_bond = 0 if len(
|
|
1102
|
+
cells_around_bond) > 1 else 1 # a bit hacky but since anyways it is saved as an int in the sqlite database then no pb to have it directly written as 0 and 1 instead of True and False
|
|
1103
|
+
# i need the coords of these vertices --> where are they
|
|
1104
|
+
# if first_vx[0] == height-1 or first_vx[0] == 0 or first_vx[1] == 0 or first_vx[1]==width-1 or second_vertex[0] == height-1 or second_vertex[0] == 0 or second_vertex[1] == 0 or second_vertex[1]==width-1:
|
|
1105
|
+
# is_border_bond = 1
|
|
1106
|
+
if first_vx in border_vertices or second_vertex in border_vertices:
|
|
1107
|
+
is_border_bond = 1
|
|
1108
|
+
|
|
1109
|
+
is_border_bond_plus_one = 0
|
|
1110
|
+
# if first_vx[0] == height-2 or first_vx[0] == 1 or first_vx[1] == 1 or first_vx[1]==width-2 or second_vertex[0] == height-2 or second_vertex[0] == 1 or second_vertex[1] == 1 or second_vertex[1]==width-2:
|
|
1111
|
+
# is_border_bond_plus_one = 1
|
|
1112
|
+
if first_vx in border_vertices_plus_one or second_vertex in border_vertices_plus_one:
|
|
1113
|
+
is_border_bond_plus_one = 1
|
|
1114
|
+
|
|
1115
|
+
# print(type(is_border_bond))
|
|
1116
|
+
bonds_2D['is_border'].append(is_border_bond)
|
|
1117
|
+
bonds_2D['is_border_plus_one'].append(is_border_bond_plus_one)
|
|
1118
|
+
|
|
1119
|
+
# get common ids around the two vertices --> recommended for pairs of vertices
|
|
1120
|
+
# qsqdqd
|
|
1121
|
+
# or get two ids around fisrt pixel --> would also work here
|
|
1122
|
+
|
|
1123
|
+
bonds_2D['orientation'].append(bd_orientation)
|
|
1124
|
+
|
|
1125
|
+
if len(original_image.shape) >= 3:
|
|
1126
|
+
for ccc in range(original_image.shape[-1]):
|
|
1127
|
+
# print('TODO sum_bd_intensity,avg_bd_intensity', sum_bd_intensity[ccc], avg_bd_intensity[ccc])
|
|
1128
|
+
if 'sum_px_int_vertices_included_ch' + str(ccc) not in bonds_2D:
|
|
1129
|
+
bonds_2D['sum_px_int_vertices_included_ch' + str(ccc)] = []
|
|
1130
|
+
bonds_2D['avg_px_int_vertices_included_ch' + str(ccc)] = []
|
|
1131
|
+
bonds_2D['sum_px_int_vertices_included_ch' + str(ccc)].append(sum_bd_intensity[ccc])
|
|
1132
|
+
bonds_2D['avg_px_int_vertices_included_ch' + str(ccc)].append(avg_bd_intensity[ccc])
|
|
1133
|
+
else:
|
|
1134
|
+
if 'sum_px_int_vertices_included_ch' + str(0) not in bonds_2D:
|
|
1135
|
+
bonds_2D['sum_px_int_vertices_included_ch' + str(0)] = []
|
|
1136
|
+
bonds_2D['avg_px_int_vertices_included_ch' + str(0)] = []
|
|
1137
|
+
bonds_2D['sum_px_int_vertices_included_ch' + str(0)].append(sum_bd_intensity)
|
|
1138
|
+
bonds_2D['avg_px_int_vertices_included_ch' + str(0)].append(avg_bd_intensity)
|
|
1139
|
+
|
|
1140
|
+
if measure_3D and height_map is not None:
|
|
1141
|
+
bonds_3D['length3D'].append(bd_length3D)
|
|
1142
|
+
#
|
|
1143
|
+
# if __DEBUG__:
|
|
1144
|
+
# print('debug #12')
|
|
1145
|
+
|
|
1146
|
+
# count nb of neighbs
|
|
1147
|
+
# will need to remove as many bonds below cutoff --> whole bond then serves as a vertex obviously...
|
|
1148
|
+
|
|
1149
|
+
# TODO get the vertices then almost all done in fact
|
|
1150
|
+
|
|
1151
|
+
# can I get the vertices per image -> ce seront juste tow added points and then I can associate this ID there
|
|
1152
|
+
# tst = np.zeros_like(img, dtype=np.uint8)
|
|
1153
|
+
# tst = original_image[reg[idx].coords[:, 0], reg[idx].coords[:, 1]]
|
|
1154
|
+
|
|
1155
|
+
# print(tst.shape) # ---> 41,
|
|
1156
|
+
|
|
1157
|
+
# plt.imshow( tst)
|
|
1158
|
+
# plt.show()
|
|
1159
|
+
|
|
1160
|
+
# print('sum_bd_intensity, avg_bd_intensity', sum_bd_intensity, avg_bd_intensity)
|
|
1161
|
+
|
|
1162
|
+
# I am almost there this time!!!
|
|
1163
|
+
|
|
1164
|
+
# when I will add bonds at the margin i will create errors --> need temporarily remove them then bring them back --> TODO
|
|
1165
|
+
|
|
1166
|
+
# if bbox touches an extremity --> just remove stuff
|
|
1167
|
+
|
|
1168
|
+
# en fait j'y suis presque
|
|
1169
|
+
|
|
1170
|
+
# easy to sort the pixels as any pixel touching the border is my real starting point in fact --> easy to fix in fact and to sort
|
|
1171
|
+
# --> juts need transform fake coords into real ones --> should be easy --> just try but maybe not that hard
|
|
1172
|
+
|
|
1173
|
+
# could also easily compute polarity
|
|
1174
|
+
|
|
1175
|
+
# very good --> just need the cantor stuff here!!!
|
|
1176
|
+
|
|
1177
|
+
# or scan along border and count neighbs if exactly 2 colors --> this is a bond --> how do I give it an id --> define a forbidden color that represent the border of the image and can then apply the cantor formula --> could be a way todo that
|
|
1178
|
+
# or increment
|
|
1179
|
+
|
|
1180
|
+
# to find bonds at edges I need to scan in lines until I find vertices ??? then change idea
|
|
1181
|
+
# in fact those bonds are splitted --> think if that is true or not
|
|
1182
|
+
|
|
1183
|
+
# need apply id to bonds to get things to work perfectly --> TODO maybe
|
|
1184
|
+
# all is ok soon
|
|
1185
|
+
|
|
1186
|
+
# bonds = np.zeros_like(vertices)
|
|
1187
|
+
# bonds[vertices==128]=128 # make a bond specific file
|
|
1188
|
+
# vertices[vertices==128]=0 # make a vertex specific file
|
|
1189
|
+
# plt.imshow(vertices)
|
|
1190
|
+
# plt.show()
|
|
1191
|
+
|
|
1192
|
+
# TODO just need the cantor coloring of bonds !!! --> TODO --> shall I do a generic filter or ignore in fact and just do cantor on the colored image directly
|
|
1193
|
+
# plt.imshow(bonds)
|
|
1194
|
+
# plt.show()
|
|
1195
|
+
|
|
1196
|
+
# plt.imshow(lab_cells)
|
|
1197
|
+
# plt.show()
|
|
1198
|
+
|
|
1199
|
+
# can I do that before cells as I need that for computing nb of neighbors !!! --> I think yes
|
|
1200
|
+
# I need associate to cell id in order to lower their counts
|
|
1201
|
+
|
|
1202
|
+
# new position #############################
|
|
1203
|
+
|
|
1204
|
+
lab_vertices = label(vertices, connectivity=2, background=0)
|
|
1205
|
+
rps_verts = regionprops(lab_vertices)
|
|
1206
|
+
|
|
1207
|
+
if __DEBUG__:
|
|
1208
|
+
print('debug #14')
|
|
1209
|
+
|
|
1210
|
+
# could simply get their ID and length between them --> quite easy in fact --> compute 2D distance in fact
|
|
1211
|
+
# pairs_of_vertices = []
|
|
1212
|
+
# detect tiny bonds that just consist of exactly two pixels --> TODO
|
|
1213
|
+
for vertex in rps_verts:
|
|
1214
|
+
if early_stop.stop == True:
|
|
1215
|
+
# print('early stop')
|
|
1216
|
+
return
|
|
1217
|
+
if vertex.area >= 2:
|
|
1218
|
+
# we have found a vertex pair --> need fix it
|
|
1219
|
+
# print('pair found', vertex.area, vertex.coords)
|
|
1220
|
+
|
|
1221
|
+
# if more than 2 --> can have trouble (is that even possible ??? I don't think so but would really need to check
|
|
1222
|
+
if vertex.area > 2: # in fact that is easy I could split it into n closest pairs of points --> that should work, but first let's see if it is possible or not ???
|
|
1223
|
+
# logger.error('error please contact baigouy@gmail.com to let him know that up to '+str(vertex.area)+ 'vertices can be adjacent to each other and provide him with a test image so that he can fix the bug'+str( vertex.coords))
|
|
1224
|
+
# sys.exit(0)
|
|
1225
|
+
|
|
1226
|
+
# array([[154, 519],
|
|
1227
|
+
# [155, 518],
|
|
1228
|
+
# [156, 519]]))
|
|
1229
|
+
|
|
1230
|
+
# need sort the three points by distance
|
|
1231
|
+
|
|
1232
|
+
# more than ntwo vertices are found side by side --> these are series of four ways vertices adjacent to each others --> sort them and split them into pairs and parse them
|
|
1233
|
+
sorted = pavlidis(vertex)
|
|
1234
|
+
|
|
1235
|
+
# print(sorted)
|
|
1236
|
+
# print(compute_distance_between_consecutive_points(sorted))
|
|
1237
|
+
# now that the list is sorted I need parse it 2 by 2 --> if I do so this is generic and i will have no pb
|
|
1238
|
+
|
|
1239
|
+
# sqdsqdsqd
|
|
1240
|
+
# TODO need a fix for that too cause very important
|
|
1241
|
+
# sort vertices by distance --> just make sure they are all sorted
|
|
1242
|
+
# need sort them so that I minimize the
|
|
1243
|
+
|
|
1244
|
+
lst = sorted
|
|
1245
|
+
else:
|
|
1246
|
+
# if bond_cut_off is not None:
|
|
1247
|
+
# if vertex.area<=bond_cut_off:
|
|
1248
|
+
# nb_of_vertices_or_neighbours_cut_off-=1
|
|
1249
|
+
|
|
1250
|
+
# print(type(vertex.coords)) # --> np.ndarray
|
|
1251
|
+
# print(type(vertex.coords.tolist()))
|
|
1252
|
+
lst = vertex.coords.tolist()
|
|
1253
|
+
# print('sls lsts ', lst)
|
|
1254
|
+
# print(len(lst)) # --> 2 --> juste deux points que je pourrais ajouter à une table --> en fait ce serait assez facile
|
|
1255
|
+
# faudra tt sauver dans du vectoriel et tt plotter
|
|
1256
|
+
# permettre du plot as bonds ou alike
|
|
1257
|
+
# faire un image compositer basique et plus puissant, un plotteur de fleches et de nematic et de vecteur et de trait --> TODO then all will be done --> then I will have even something better than TA and simpler to use and that can be command line driven
|
|
1258
|
+
|
|
1259
|
+
# peut etre faire un object qui calcule et ecrit ttes les propriétés des objets --> facile à handler je pense --> quite a good idea I think
|
|
1260
|
+
# call area cytoplasmic_area
|
|
1261
|
+
# area being (cytoplasmic area + 2 perimeter_area/2)
|
|
1262
|
+
# maybe have a header that explains it all what the measures are
|
|
1263
|
+
# maybe allow plots in ROIs and or in clones
|
|
1264
|
+
# TODO --> some day
|
|
1265
|
+
# pairs_of_vertices.append(lst)
|
|
1266
|
+
|
|
1267
|
+
# need get the ids of the vertices and invent a local id --> max of previous --> TODO
|
|
1268
|
+
|
|
1269
|
+
# print('ids sdqsdqs',ids)
|
|
1270
|
+
|
|
1271
|
+
# print('pairs of vertices', lst)
|
|
1272
|
+
# print('perimeter2D',vertex.perimeter) # why always 0 ??? --> shall I compute it myself # compute distance 2D --> clearly the perimeter algo of scipy does not work in such case
|
|
1273
|
+
# print('length',distance_between_points(lst[0], lst[-1]))
|
|
1274
|
+
# print('pixel_count', len(lst))
|
|
1275
|
+
# print('vx_1', ids[0])
|
|
1276
|
+
# print('vx_2', ids[-1])
|
|
1277
|
+
|
|
1278
|
+
# do it generically by pairs of points
|
|
1279
|
+
# convert a list to another list of pairs and execute the code below!!!
|
|
1280
|
+
# pair each element with the next in the list and loop over this!!
|
|
1281
|
+
|
|
1282
|
+
pairs = list(zip(lst, lst[1:]))
|
|
1283
|
+
# if len(lst) == 3:
|
|
1284
|
+
#
|
|
1285
|
+
# print('lst',lst)
|
|
1286
|
+
# print('pairs', pairs)
|
|
1287
|
+
# print(compute_distance_between_consecutive_points(lst))
|
|
1288
|
+
|
|
1289
|
+
# print('before', locally_labeled_vertices[vertex.coords[:, 0], vertex.coords[:, 1]])
|
|
1290
|
+
|
|
1291
|
+
for lst in pairs:
|
|
1292
|
+
# again changing this code will be a pain... because very long
|
|
1293
|
+
crds = np.asarray(lst)
|
|
1294
|
+
# need get the id locally
|
|
1295
|
+
ids = locally_labeled_vertices[crds[:, 0], crds[:, 1]] # this works and is generic
|
|
1296
|
+
# print('after', ids)
|
|
1297
|
+
max_bond_id += 1
|
|
1298
|
+
|
|
1299
|
+
# print('lst',lst)
|
|
1300
|
+
|
|
1301
|
+
bonds_2D['local_ID'].append(max_bond_id)
|
|
1302
|
+
# bonds_3D['local_ID'].append(max_bond_id) # --> maybe add id --> also so that one can pair it with the other db --> see what I can do!!!
|
|
1303
|
+
bonds_2D['length'].append(
|
|
1304
|
+
distance_between_points(lst[0], lst[-1])) # pb is here I need more to be generic...
|
|
1305
|
+
bonds_2D['pixel_count'].append(len(lst))
|
|
1306
|
+
|
|
1307
|
+
bonds_2D['vx_1'].append(ids[0])
|
|
1308
|
+
bonds_2D['vx_2'].append(ids[-1])
|
|
1309
|
+
|
|
1310
|
+
# bonds_2D['cell_id1_around_bond'].append(cells_around_bond[0])
|
|
1311
|
+
# bonds_2D['cell_id2_around_bond'].append(cells_around_bond[-1]) # --> TODO but a bit more complex in fact !!!
|
|
1312
|
+
bd_orientation = get_orientation(lst[0], lst[-1])
|
|
1313
|
+
bonds_2D['orientation'].append(
|
|
1314
|
+
bd_orientation) # --> although largely meaningless...
|
|
1315
|
+
|
|
1316
|
+
# TODO --> here too
|
|
1317
|
+
# bonds_2D['cell_id1_around_bond'].append(cells_around_bond[0])
|
|
1318
|
+
# bonds_2D['cell_id2_around_bond'].append(cells_around_bond[-1]) # --> TODO but a bit more complex in fact !!!
|
|
1319
|
+
|
|
1320
|
+
# TODO need do that also with list because this is gonna be wrong
|
|
1321
|
+
|
|
1322
|
+
# this will be wrong --> need fix it
|
|
1323
|
+
sum_bd_intensity, avg_bd_intensity = get_sum_and_avg_intensity(original_image,
|
|
1324
|
+
crds) # this line will be wrong --> need fix it
|
|
1325
|
+
if len(original_image.shape) >= 3:
|
|
1326
|
+
for ccc in range(original_image.shape[-1]):
|
|
1327
|
+
# print('TODO sum_bd_intensity,avg_bd_intensity', sum_bd_intensity[ccc], avg_bd_intensity[ccc])
|
|
1328
|
+
if 'sum_px_int_vertices_included_ch' + str(ccc) not in bonds_2D:
|
|
1329
|
+
bonds_2D['sum_px_int_vertices_included_ch' + str(ccc)] = []
|
|
1330
|
+
bonds_2D['avg_px_int_vertices_included_ch' + str(ccc)] = []
|
|
1331
|
+
bonds_2D['sum_px_int_vertices_included_ch' + str(ccc)].append(sum_bd_intensity[ccc])
|
|
1332
|
+
bonds_2D['avg_px_int_vertices_included_ch' + str(ccc)].append(avg_bd_intensity[ccc])
|
|
1333
|
+
else:
|
|
1334
|
+
if 'sum_px_int_vertices_included_ch' + str(0) not in bonds_2D:
|
|
1335
|
+
bonds_2D['sum_px_int_vertices_included_ch' + str(0)] = []
|
|
1336
|
+
bonds_2D['avg_px_int_vertices_included_ch' + str(0)] = []
|
|
1337
|
+
bonds_2D['sum_px_int_vertices_included_ch' + str(0)].append(sum_bd_intensity)
|
|
1338
|
+
bonds_2D['avg_px_int_vertices_included_ch' + str(0)].append(avg_bd_intensity)
|
|
1339
|
+
|
|
1340
|
+
# not so hard to do I guess because I have id and bond id
|
|
1341
|
+
|
|
1342
|
+
# CHECK NEIGHBORHOOD TO FIND id -> need get common ids
|
|
1343
|
+
# can this stuff be a border bond ??? --> I guess not but maybe --> need think further about it!!!
|
|
1344
|
+
|
|
1345
|
+
cells_around_vx1 = set(
|
|
1346
|
+
neighbors8(lst[0],
|
|
1347
|
+
lab_cells)) # nb this is another way of detecting border cells!!!vertex.coords[0]
|
|
1348
|
+
cells_around_vx2 = set(
|
|
1349
|
+
neighbors8(lst[-1],
|
|
1350
|
+
lab_cells)) # nb this is another way of detecting border cells!!! #vertex.coords[1]
|
|
1351
|
+
# get common cells of the set --> these are the two ids of the cells sharing this mini bond
|
|
1352
|
+
cells_around_bond = cells_around_vx1.intersection(cells_around_vx2)
|
|
1353
|
+
if 0 in cells_around_bond:
|
|
1354
|
+
cells_around_bond.remove(0)
|
|
1355
|
+
cells_around_bond = list(cells_around_bond)
|
|
1356
|
+
|
|
1357
|
+
if len(cells_around_bond) > 2:
|
|
1358
|
+
print('pairs of vertices have too many cells in common, please report error to benoit.aigouy@gmail.com')
|
|
1359
|
+
# print('cells_around_bond',cells_around_bond, cells_around_vx1, cells_around_vx2)
|
|
1360
|
+
# cells_around_bond
|
|
1361
|
+
|
|
1362
|
+
if cells_around_bond:
|
|
1363
|
+
bonds_2D['cell_id1_around_bond'].append(cells_around_bond[0])
|
|
1364
|
+
bonds_2D['cell_id2_around_bond'].append(cells_around_bond[-1])
|
|
1365
|
+
else:
|
|
1366
|
+
bonds_2D['cell_id1_around_bond'].append(None)
|
|
1367
|
+
bonds_2D['cell_id2_around_bond'].append(None)
|
|
1368
|
+
|
|
1369
|
+
# bonds_2D['cell_id1_around_bond'].append(cells_around_bond[0])
|
|
1370
|
+
# bonds_2D['cell_id2_around_bond'].append(cells_around_bond[-1])
|
|
1371
|
+
is_border_bond = 0 if len(
|
|
1372
|
+
cells_around_bond) > 1 else 1 # a bit hacky but since anyways it is saved as an int in the sqlite database then no pb to have it directly written as 0 and 1 instead of True and False
|
|
1373
|
+
|
|
1374
|
+
if first_vx in border_vertices or second_vertex in border_vertices:
|
|
1375
|
+
is_border_bond = 1
|
|
1376
|
+
|
|
1377
|
+
is_border_bond_plus_one = 0
|
|
1378
|
+
# if first_vx[0] == height-2 or first_vx[0] == 1 or first_vx[1] == 1 or first_vx[1]==width-2 or second_vertex[0] == height-2 or second_vertex[0] == 1 or second_vertex[1] == 1 or second_vertex[1]==width-2:
|
|
1379
|
+
# is_border_bond_plus_one = 1
|
|
1380
|
+
if first_vx in border_vertices_plus_one or second_vertex in border_vertices_plus_one:
|
|
1381
|
+
is_border_bond_plus_one = 1
|
|
1382
|
+
|
|
1383
|
+
# print(type(is_border_bond))
|
|
1384
|
+
bonds_2D['is_border'].append(is_border_bond)
|
|
1385
|
+
bonds_2D['is_border_plus_one'].append(is_border_bond_plus_one)
|
|
1386
|
+
|
|
1387
|
+
# print(type(is_border_bond))
|
|
1388
|
+
# bonds_2D['is_border'].append(is_border_bond)
|
|
1389
|
+
|
|
1390
|
+
# check if real and really normal
|
|
1391
|
+
if cells_around_bond:
|
|
1392
|
+
if cells_around_bond[0] not in bonds_associated_to_a_given_cell:
|
|
1393
|
+
bonds_associated_to_a_given_cell[cells_around_bond[0]] = []
|
|
1394
|
+
bond_lengths_associated_to_a_given_cell[cells_around_bond[0]] = []
|
|
1395
|
+
bonds_associated_to_a_given_cell[cells_around_bond[0]].append(max_bond_id)
|
|
1396
|
+
bond_lengths_associated_to_a_given_cell[cells_around_bond[0]].append(len(lst))
|
|
1397
|
+
if cells_around_bond[-1] != cells_around_bond[0]:
|
|
1398
|
+
if cells_around_bond[-1] not in bonds_associated_to_a_given_cell:
|
|
1399
|
+
bonds_associated_to_a_given_cell[cells_around_bond[-1]] = []
|
|
1400
|
+
bond_lengths_associated_to_a_given_cell[cells_around_bond[-1]] = []
|
|
1401
|
+
bonds_associated_to_a_given_cell[cells_around_bond[-1]].append(max_bond_id)
|
|
1402
|
+
bond_lengths_associated_to_a_given_cell[cells_around_bond[-1]].append(len(lst))
|
|
1403
|
+
|
|
1404
|
+
# new position #############################
|
|
1405
|
+
|
|
1406
|
+
if __DEBUG__:
|
|
1407
|
+
print('debug #15')
|
|
1408
|
+
|
|
1409
|
+
rps = regionprops(lab_cells, intensity_image=original_image)
|
|
1410
|
+
|
|
1411
|
+
# ça marche mais ne detecte qd meme pas ts les vertices
|
|
1412
|
+
# faire un detecteur de vertex à la boundary --> useful and put bonds there too --> simpler in fact
|
|
1413
|
+
|
|
1414
|
+
# draw a small shape just to see
|
|
1415
|
+
# le code de perimeter de scipy est bon --> cool
|
|
1416
|
+
|
|
1417
|
+
cells[cells != 0] = 1
|
|
1418
|
+
|
|
1419
|
+
# in fact if image is passed in I can directly get avg intensity --> easy peasy
|
|
1420
|
+
# --> TODO
|
|
1421
|
+
# set in fact do on a channel by channel basis
|
|
1422
|
+
|
|
1423
|
+
for cell in rps:
|
|
1424
|
+
if early_stop.stop == True:
|
|
1425
|
+
# print('early stop')
|
|
1426
|
+
return
|
|
1427
|
+
|
|
1428
|
+
# print('wrong perimeter',cell.perimeter) # --> 94.14213562373095 vs 95.799 in IJ --> no clue how they do that and need check the real one --> maybe this is ok in fact because I count 97 in fact for outer
|
|
1429
|
+
# manually computed for the circle:
|
|
1430
|
+
# print(math.sqrt(2) * 8 + 2 * 4) # same perimeter but --> needs contour --> i need find the countour first then it is gonna be ok
|
|
1431
|
+
|
|
1432
|
+
# as expected --> in IJ perimeter is completely wrong... and really makes no sense to me...
|
|
1433
|
+
|
|
1434
|
+
# https://stackoverflow.com/questions/12747319/scipy-label-dilation --> maybe exactly what I want in fact
|
|
1435
|
+
|
|
1436
|
+
# plt.imshow(cell.filled_image) # --> ok this is what I want in fact but it is cropped --> need pad and have bounding box to compute coords of dilation
|
|
1437
|
+
# plt.show()
|
|
1438
|
+
|
|
1439
|
+
# what I could do is pas the image and dilate it and then just get the mask in the original image for that exact region and measure its perimeter
|
|
1440
|
+
# and or sort it and compute the 3D perimeter!!!
|
|
1441
|
+
# TODO
|
|
1442
|
+
|
|
1443
|
+
# seems ok I think
|
|
1444
|
+
# plt.imshow(cell.image)
|
|
1445
|
+
# plt.title('toto')
|
|
1446
|
+
# plt.show()
|
|
1447
|
+
|
|
1448
|
+
# maybe need change structuring element though
|
|
1449
|
+
# plt.imshow(ndimage.binary_dilation(cell.image))
|
|
1450
|
+
# plt.show()
|
|
1451
|
+
bbox = cell.bbox
|
|
1452
|
+
# print(cell.bbox)
|
|
1453
|
+
#
|
|
1454
|
+
|
|
1455
|
+
# img = np.pad(cell.image, tuple(cell.image.shape[0]+2, cell.image.shape[1]+2), mode='constant', constant_values=False)
|
|
1456
|
+
# img = np.pad(cell.image, tuple(cell.image.shape[0]+2, cell.image.shape[1]+2), mode='constant', constant_values=False)
|
|
1457
|
+
img = np.pad(cell.image, pad_width=1, mode='constant', constant_values=False)
|
|
1458
|
+
# print(cell.perimeter_crofton) --> not good at all --> forget
|
|
1459
|
+
|
|
1460
|
+
# struct2 = ndimage.generate_binary_structure(2, 2) # --> better because would get TA vertices because it gets the borders
|
|
1461
|
+
# print(struct2)
|
|
1462
|
+
# dilated_mask = ndimage.binary_dilation(img, structure=struct2)
|
|
1463
|
+
dilated_mask = ndimage.binary_dilation(img)
|
|
1464
|
+
|
|
1465
|
+
dilated_mask ^= np.pad(cell.image, pad_width=1, mode='constant', constant_values=False)
|
|
1466
|
+
|
|
1467
|
+
# seems exactly what I want in fact --> do I even need more ????
|
|
1468
|
+
|
|
1469
|
+
# dilated_mask[vertices[bbox[0]:bbox[2] + 2, bbox[1]: bbox[3] + 2] == 255] = True # add vertices to the mask because they are not captured by the dilation
|
|
1470
|
+
|
|
1471
|
+
# x_shift_to_transfrom_local_coords_to_global_coords = bbox[1] - 1
|
|
1472
|
+
# y_shift_to_transfrom_local_coords_to_global_coords = bbox[0] - 1
|
|
1473
|
+
|
|
1474
|
+
# ça marche c'est sans les vertices
|
|
1475
|
+
# if cell.label == 6:
|
|
1476
|
+
# # the dialted mask seems be correct
|
|
1477
|
+
# plt.imshow(dilated_mask)
|
|
1478
|
+
# plt.show()
|
|
1479
|
+
|
|
1480
|
+
dilated_mask[vertices[bbox[0] - 1:bbox[2] + 1, bbox[1] - 1: bbox[
|
|
1481
|
+
3] + 1] == 255] = True # add vertices to the mask because they are not captured by the dilation
|
|
1482
|
+
# the pb here is that some vertices are outside the cell which does not make sense and is dangerous for the label
|
|
1483
|
+
|
|
1484
|
+
# ça marche --> avec les vertices
|
|
1485
|
+
# if cell.label == 6:
|
|
1486
|
+
# the dialted mask seems be correct
|
|
1487
|
+
# plt.imshow(dilated_mask)
|
|
1488
|
+
# plt.show()
|
|
1489
|
+
|
|
1490
|
+
lab_perim = label(dilated_mask, connectivity=2)
|
|
1491
|
+
reg = regionprops(lab_perim)
|
|
1492
|
+
|
|
1493
|
+
idx = 0
|
|
1494
|
+
if len(reg) != 1:
|
|
1495
|
+
# Too many cells detected --> needs a fix --> need take the biggest one or need a trick
|
|
1496
|
+
# print('error wrong length', cell.label)
|
|
1497
|
+
# plt.imshow(lab_perim)
|
|
1498
|
+
# plt.show()
|
|
1499
|
+
# need a fix if vertex is outside the cell
|
|
1500
|
+
|
|
1501
|
+
max_area = 0
|
|
1502
|
+
for ppp, perim in enumerate(reg):
|
|
1503
|
+
if perim.area > max_area:
|
|
1504
|
+
max_area = perim.area
|
|
1505
|
+
idx = ppp
|
|
1506
|
+
|
|
1507
|
+
# print('fixed index', idx, cell.label)
|
|
1508
|
+
|
|
1509
|
+
# if cell.label == 6:
|
|
1510
|
+
# # the bug is because of two cells due to the presence of a vertex --> if len is not 0 --> need take the biggest I guess
|
|
1511
|
+
# plt.imshow(lab_perim)
|
|
1512
|
+
# plt.show()
|
|
1513
|
+
|
|
1514
|
+
# print('real_perimeter', reg[idx].perimeter, reg[idx].area) # nb half of this area needs be added to the cell area in fact # , reg[0].perimeter_crofton) # --> probably ok but if I need compute intensities I need place it back --> can replace it in several of my codes
|
|
1515
|
+
|
|
1516
|
+
# need sort pixels to recover the real polarity nematic of the cell
|
|
1517
|
+
|
|
1518
|
+
# c'est plutot long (ça double le temps mais pas si mal car me permet de calculer le perimeter 3D et de
|
|
1519
|
+
# faire une table appelee measurements 3D
|
|
1520
|
+
# faire une table appelee measurements 3D
|
|
1521
|
+
# permettre des natural joins de pleins de tables en fait --> un peu plus flexible et modulaire qu'avant
|
|
1522
|
+
# faire un calcul de l'intensite du cytoplasme aussi --> pas trop dur en fait à faire
|
|
1523
|
+
|
|
1524
|
+
# TODO make this optional --> required for polarity and also for 3D
|
|
1525
|
+
|
|
1526
|
+
# print('reg[0].coords',reg[0].coords)
|
|
1527
|
+
#
|
|
1528
|
+
# print('sorted_contour', sorted_contour)
|
|
1529
|
+
|
|
1530
|
+
# # measure 3D perimeter
|
|
1531
|
+
# y_shift_to_transfrom_local_coords_to_global_coords = bbox[0] - 1
|
|
1532
|
+
# x_shift_to_transfrom_local_coords_to_global_coords = bbox[1] - 1
|
|
1533
|
+
|
|
1534
|
+
# need translate all the contour points
|
|
1535
|
+
y_shift_to_transfrom_local_coords_to_global_coords = bbox[0] - 1
|
|
1536
|
+
x_shift_to_transfrom_local_coords_to_global_coords = bbox[1] - 1
|
|
1537
|
+
|
|
1538
|
+
if measure_3D or measure_polarity:
|
|
1539
|
+
sorted_contour = pavlidis(reg[idx], closed_contour=True)
|
|
1540
|
+
# need correct coords of sorted contour --> this must also be done before computing polarity!!!
|
|
1541
|
+
sorted_contour = [
|
|
1542
|
+
[y + y_shift_to_transfrom_local_coords_to_global_coords,
|
|
1543
|
+
x + x_shift_to_transfrom_local_coords_to_global_coords]
|
|
1544
|
+
for y, x in sorted_contour]
|
|
1545
|
+
|
|
1546
|
+
if measure_polarity:
|
|
1547
|
+
# compute polarity nematic:
|
|
1548
|
+
centoid_corrected = [reg[idx].centroid[0] + y_shift_to_transfrom_local_coords_to_global_coords,
|
|
1549
|
+
reg[idx].centroid[1] + x_shift_to_transfrom_local_coords_to_global_coords]
|
|
1550
|
+
|
|
1551
|
+
# is that because the contour is not corrected ???
|
|
1552
|
+
polarity_nematic = compute_polarity_nematic(centoid_corrected, sorted_contour, original_image)
|
|
1553
|
+
|
|
1554
|
+
# print(polarity_nematic, centoid_corrected) # centroid is correct but there is a bug in the polarity
|
|
1555
|
+
# need save the data for every channel in the db --> TODO
|
|
1556
|
+
|
|
1557
|
+
# print('polarity nematic', polarity_nematic) # TODO DO THIS FOR ALL CHANNELS
|
|
1558
|
+
|
|
1559
|
+
if measure_3D and height_map is not None:
|
|
1560
|
+
# measure 3D perimeter
|
|
1561
|
+
|
|
1562
|
+
# print('sorted_bond perim3D', sorted_contour)
|
|
1563
|
+
perimeter3D = perimeter_3D(sorted_contour, heightmap=height_map, points_are_sorted=True,
|
|
1564
|
+
is_closed_contour=False)
|
|
1565
|
+
# print('perimeter3D', perimeter3D)
|
|
1566
|
+
|
|
1567
|
+
# TODO allow intensity measurements here too
|
|
1568
|
+
|
|
1569
|
+
# print('plenty of measurements')
|
|
1570
|
+
# print(cell.mean_intensity, cell.max_intensity, cell.min_intensity)
|
|
1571
|
+
# print(cell.weighted_centroid, cell.centroid)
|
|
1572
|
+
# print('first point', cell.coords[0][0], cell.coords[0][1])
|
|
1573
|
+
|
|
1574
|
+
# get cell vertices here
|
|
1575
|
+
vertices_indices_cells = np.nonzero(vertices[
|
|
1576
|
+
reg[idx].coords[:,
|
|
1577
|
+
0] + y_shift_to_transfrom_local_coords_to_global_coords,
|
|
1578
|
+
reg[idx].coords[:,
|
|
1579
|
+
1] + x_shift_to_transfrom_local_coords_to_global_coords])[
|
|
1580
|
+
0].tolist()
|
|
1581
|
+
|
|
1582
|
+
# if len(vertices_indices) > 2:
|
|
1583
|
+
# logger.error(
|
|
1584
|
+
# 'error: wrong number of vertices --> please report this to baigouy@gmail.com' + str(vertices_indices))
|
|
1585
|
+
#
|
|
1586
|
+
# # print('neo vertices', vertices_indices) # this gives me the indices of the vertices of the bonds --> see how I can associate them with a cell at some point maybe if necessary
|
|
1587
|
+
# first_vertex = (reg[idx].coords[vertices_indices[0], 0] + y_shift_to_transfrom_local_coords_to_global_coords,
|
|
1588
|
+
# reg[idx].coords[vertices_indices[0], 1] + x_shift_to_transfrom_local_coords_to_global_coords)
|
|
1589
|
+
# second_vertex = (reg[idx].coords[vertices_indices[-1], 0] + y_shift_to_transfrom_local_coords_to_global_coords,
|
|
1590
|
+
# reg[idx].coords[vertices_indices[-1], 1] + x_shift_to_transfrom_local_coords_to_global_coords)
|
|
1591
|
+
|
|
1592
|
+
# could in fact just get vertices local id and then can be recovered using joins
|
|
1593
|
+
# maybe sort the ids ????
|
|
1594
|
+
# print('neo vertices_indices_cells', vertices_indices_cells)
|
|
1595
|
+
|
|
1596
|
+
# plt.imshow(vertices)
|
|
1597
|
+
# plt.show()
|
|
1598
|
+
# print('oubs',vertices_indices_cells, len( reg[idx].coords), idx)# why None
|
|
1599
|
+
|
|
1600
|
+
vx_local_ids = []
|
|
1601
|
+
for cell_vertex in vertices_indices_cells:
|
|
1602
|
+
# print(idx, len(reg), cell_vertex, len(reg[idx].coords))
|
|
1603
|
+
# print(reg[idx])
|
|
1604
|
+
# print(vertices_indices_cells[cell_vertex])
|
|
1605
|
+
y = reg[idx].coords[cell_vertex, 0] + y_shift_to_transfrom_local_coords_to_global_coords,
|
|
1606
|
+
x = reg[idx].coords[cell_vertex, 1] + x_shift_to_transfrom_local_coords_to_global_coords,
|
|
1607
|
+
vx_local_ids.append(locally_labeled_vertices[y, x][0])
|
|
1608
|
+
# qsdqsdqsd
|
|
1609
|
+
|
|
1610
|
+
bond_indices_cells = list(set(lab_bonds[
|
|
1611
|
+
reg[idx].coords[:,
|
|
1612
|
+
0] + y_shift_to_transfrom_local_coords_to_global_coords,
|
|
1613
|
+
reg[idx].coords[:,
|
|
1614
|
+
1] + x_shift_to_transfrom_local_coords_to_global_coords].tolist()))
|
|
1615
|
+
if 0 in bond_indices_cells:
|
|
1616
|
+
bond_indices_cells.remove(0)
|
|
1617
|
+
# bond_local_ID = []
|
|
1618
|
+
|
|
1619
|
+
# print('bond_indices_cells',bond_indices_cells) # this contains all 'long' bonds of the current cell
|
|
1620
|
+
|
|
1621
|
+
if cell.label not in bonds_associated_to_a_given_cell:
|
|
1622
|
+
bonds_associated_to_a_given_cell[cell.label] = []
|
|
1623
|
+
bond_lengths_associated_to_a_given_cell[cell.label] = []
|
|
1624
|
+
bonds_associated_to_a_given_cell[cell.label].extend(bond_indices_cells)
|
|
1625
|
+
# need add all the bond lengthes corresponding to these values --> TODO
|
|
1626
|
+
for bd_id in bond_indices_cells:
|
|
1627
|
+
bond_lengths_associated_to_a_given_cell[cell.label].append(local_bond_ID_and_px_count[bd_id])
|
|
1628
|
+
# if I now store the length of the bonds i can easily get the apcking
|
|
1629
|
+
|
|
1630
|
+
# split by comma for example
|
|
1631
|
+
# print('vx_local_ids',vx_local_ids)
|
|
1632
|
+
|
|
1633
|
+
# T0D0 NEED A 3D version of this
|
|
1634
|
+
point_awlays_inside_the_cell = point_on_surface(cell, lab_cells)
|
|
1635
|
+
# print('point inside cell', point_awlays_inside_the_cell)
|
|
1636
|
+
|
|
1637
|
+
if measure_3D and height_map is not None:
|
|
1638
|
+
# all is ok now
|
|
1639
|
+
triangulation_centroid = point_awlays_inside_the_cell # central point for triangulation
|
|
1640
|
+
# if int(ceil(cell.centroid[0]))==point_awlays_inside_the_cell[0] and int(ceil(cell.centroid[1]))==point_awlays_inside_the_cell[1]:
|
|
1641
|
+
# now just need to triangulate the cell
|
|
1642
|
+
|
|
1643
|
+
# get the vertices of the contour and the triangulation centroid to triangulate a cell
|
|
1644
|
+
# alternatively could take all points of the contour --> maybe try both
|
|
1645
|
+
|
|
1646
|
+
# compute_3D_surfacearea
|
|
1647
|
+
|
|
1648
|
+
# print(reg[0].coords)
|
|
1649
|
+
# print('test', reg[0].coords[:,0])
|
|
1650
|
+
|
|
1651
|
+
# there is a bug in the detection of vertices at least for the border cells --> needs a fix
|
|
1652
|
+
|
|
1653
|
+
y_corrected = [y_shift_to_transfrom_local_coords_to_global_coords + y for y in reg[idx].coords[:,
|
|
1654
|
+
0].tolist()] # see how I handle the relative coords here --> do I have a bug???
|
|
1655
|
+
x_corrected = [x_shift_to_transfrom_local_coords_to_global_coords + x for x in
|
|
1656
|
+
reg[idx].coords[:, 1].tolist()]
|
|
1657
|
+
|
|
1658
|
+
verts = np.where(vertices[
|
|
1659
|
+
y_corrected, x_corrected] == 255) # TODO need add this to the cell or maybe the ids of those ??? --> good idea
|
|
1660
|
+
|
|
1661
|
+
# print(verts)
|
|
1662
|
+
|
|
1663
|
+
# vertices not found properly --> why
|
|
1664
|
+
# if cell.label == 6:
|
|
1665
|
+
# print('verts',verts, y_shift_to_transfrom_local_coords_to_global_coords,x_shift_to_transfrom_local_coords_to_global_coords)
|
|
1666
|
+
|
|
1667
|
+
y_corrected = np.asarray(y_corrected)[verts[0]]
|
|
1668
|
+
x_corrected = np.asarray(x_corrected)[verts[0]]
|
|
1669
|
+
|
|
1670
|
+
# if cell.label == 6:
|
|
1671
|
+
# print('x_corrected,y_corrected',x_corrected,y_corrected)
|
|
1672
|
+
|
|
1673
|
+
x_corrected = x_corrected.tolist()
|
|
1674
|
+
y_corrected = y_corrected.tolist()
|
|
1675
|
+
|
|
1676
|
+
# y_corrected = [y_shift_to_transfrom_local_coords_to_global_coords + y for y in verts[:, 0].tolist()]
|
|
1677
|
+
# x_corrected = [x_shift_to_transfrom_local_coords_to_global_coords + x for x in verts[:, 1].tolist()]
|
|
1678
|
+
|
|
1679
|
+
# just get coords where
|
|
1680
|
+
|
|
1681
|
+
# I think that is 100% what I want now!!!
|
|
1682
|
+
|
|
1683
|
+
# this is very fast just need heightmap and try compute 3D area just for fun, for a test try on a real sample
|
|
1684
|
+
|
|
1685
|
+
# en fait c'est à peine plus long en 3D ...
|
|
1686
|
+
|
|
1687
|
+
try:
|
|
1688
|
+
|
|
1689
|
+
# je pense qu'il y a des bugs
|
|
1690
|
+
|
|
1691
|
+
y_corrected.append(triangulation_centroid[0])
|
|
1692
|
+
x_corrected.append(triangulation_centroid[1])
|
|
1693
|
+
|
|
1694
|
+
# why so few points -> bug here
|
|
1695
|
+
points_for_triangulation = list(zip(y_corrected, x_corrected))
|
|
1696
|
+
|
|
1697
|
+
if len(points_for_triangulation) < 4:
|
|
1698
|
+
if __DEBUG__:
|
|
1699
|
+
print('not enough vertices for cell #' + str(
|
|
1700
|
+
cell.label) + ' --> trying to add a subset of contour pixels instead, in order to triangulate')
|
|
1701
|
+
logger.warning('not enough vertices for cell #' + str(
|
|
1702
|
+
cell.label) + ' --> trying to add a subset of contour pixels instead, in order to triangulate')
|
|
1703
|
+
|
|
1704
|
+
# try add n random points from the table
|
|
1705
|
+
# points_for_triangulation.append()
|
|
1706
|
+
|
|
1707
|
+
y_corrected = [y_shift_to_transfrom_local_coords_to_global_coords + y for y in reg[idx].coords[:,
|
|
1708
|
+
0].tolist()] # see how I handle the relative coords here --> do I have a bug???
|
|
1709
|
+
x_corrected = [x_shift_to_transfrom_local_coords_to_global_coords + x for x in
|
|
1710
|
+
reg[idx].coords[:, 1].tolist()]
|
|
1711
|
+
|
|
1712
|
+
# get x% random values from both
|
|
1713
|
+
# print('y_corrected, x_corrected', len(y_corrected), len(x_corrected))
|
|
1714
|
+
tmp = list(zip(y_corrected, x_corrected))
|
|
1715
|
+
|
|
1716
|
+
nb_of_point_to_get = 12 # could also take x percent of the contour --> TODO or take n points maybe as if the cell was an n sided cell --> maybe take 10 --> enough in fact
|
|
1717
|
+
# if nb_of_point_to_get<4:
|
|
1718
|
+
# nb_of_point_to_get = 4
|
|
1719
|
+
if nb_of_point_to_get > len(y_corrected):
|
|
1720
|
+
nb_of_point_to_get = len(y_corrected)
|
|
1721
|
+
|
|
1722
|
+
seleted_points = random.sample(tmp, nb_of_point_to_get)
|
|
1723
|
+
points_for_triangulation.extend(seleted_points)
|
|
1724
|
+
|
|
1725
|
+
# print('points_for_triangulation',points_for_triangulation)
|
|
1726
|
+
|
|
1727
|
+
# points_for_triangulation.append(triangulation_centroid)
|
|
1728
|
+
|
|
1729
|
+
# can I do that ???
|
|
1730
|
+
|
|
1731
|
+
# points_for_triangulation =[reg[0].coords]
|
|
1732
|
+
# there is a bug in there dunno where
|
|
1733
|
+
|
|
1734
|
+
# nb rather just take vertices because a bit bigger than the cell and mention it is an approximation
|
|
1735
|
+
# --> pas mal mais rajoute encore deux seqs de plus mais pas mal qd meme
|
|
1736
|
+
# triangles = triangulate(np.asarray(points_for_triangulation), triangulated_object_ID=cell.label, labels_to_check=lab_cells)#,triangulated_object_ID=cell.label) # need filter the triangulation for concave shapes of clones which is very frequent
|
|
1737
|
+
|
|
1738
|
+
# nb si seulement deux points --> pas de triangulation --> la question c'est pkoi seulement deux points
|
|
1739
|
+
# if cell.label == 6:
|
|
1740
|
+
# print('np.asarray(points_for_triangulation)',np.asarray(points_for_triangulation))
|
|
1741
|
+
# print('points_for_triangulation',points_for_triangulation)
|
|
1742
|
+
|
|
1743
|
+
triangles = triangulate(np.asarray(
|
|
1744
|
+
points_for_triangulation)) # ,triangulated_object_ID=cell.label) # need filter the triangulation for concave shapes of clones which is very frequent
|
|
1745
|
+
|
|
1746
|
+
# make it measure the 3D area of the clone --> TODO
|
|
1747
|
+
# if __DEBUG__:
|
|
1748
|
+
# print('area cell 3D', cell.label, compute_3D_surfacearea(triangles,
|
|
1749
|
+
# heightmap=height_map)) # --> ça marche enfin on dirait! --> cool
|
|
1750
|
+
|
|
1751
|
+
# small hack debug to make centroid same height as vertices if handcorrection is passed in --> so that all points are the same height and area is 0 in fact
|
|
1752
|
+
|
|
1753
|
+
# finally just do the length meaurement in 3D for the perimeter and bonds and i'll be done --> this will also be useful for Amrutha
|
|
1754
|
+
|
|
1755
|
+
# maybe I could also save the area for flat 3D as it will not be the same as the real area --> very good idea in fact --> quite smart in fact I really love it
|
|
1756
|
+
# height_map[triangulation_centroid[0], triangulation_centroid[1]]=255 # --> ça marche super en fait et pas de bugs
|
|
1757
|
+
# TODO define the 3D stuff
|
|
1758
|
+
|
|
1759
|
+
# if measure_3D and height_map is not None:
|
|
1760
|
+
|
|
1761
|
+
area3D_flat_3D = compute_3D_surfacearea(triangles, disable_2D_warning=True)
|
|
1762
|
+
area3D = compute_3D_surfacearea(triangles, heightmap=height_map)
|
|
1763
|
+
|
|
1764
|
+
# print('area in 3D', area3D_flat_3D, area3D,cell.area) # there has to be a bug ??? because since all at same height the area must be the same as in 2D --> check that
|
|
1765
|
+
|
|
1766
|
+
|
|
1767
|
+
# ferets_of_interest.append(area3D)
|
|
1768
|
+
|
|
1769
|
+
# seems almost ok
|
|
1770
|
+
|
|
1771
|
+
# plot_triangulation(triangles, out)
|
|
1772
|
+
# if __DEBUG__:
|
|
1773
|
+
# plot_triangulation(triangles, original_image)
|
|
1774
|
+
# plot_triangulation(triangles)
|
|
1775
|
+
except:
|
|
1776
|
+
traceback.print_exc()
|
|
1777
|
+
# clearly it misses most of the vertices of the cell --> big bug ---> see what is going wrong and why
|
|
1778
|
+
# it also fails for cells without vertices
|
|
1779
|
+
print('failed for cell2', cell.label, cell.area, cell.bbox, verts, points_for_triangulation,
|
|
1780
|
+
cell.coords)
|
|
1781
|
+
# print('np.asarray(points_for_triangulation)', np.asarray(points_for_triangulation))
|
|
1782
|
+
|
|
1783
|
+
|
|
1784
|
+
# TODO try cell triangulation for 3D --> should be easy todo in fact !!!
|
|
1785
|
+
|
|
1786
|
+
# plt.imshow(original_image)
|
|
1787
|
+
# plt.show()
|
|
1788
|
+
|
|
1789
|
+
# see what's left to be done
|
|
1790
|
+
|
|
1791
|
+
# now that I have the point inside the cell I can take it
|
|
1792
|
+
|
|
1793
|
+
# on top of cell centroid I can take a point in the cell
|
|
1794
|
+
# first point
|
|
1795
|
+
# or could take a point always in the cell for sure --> smart
|
|
1796
|
+
# coords --> can be a table named coords
|
|
1797
|
+
|
|
1798
|
+
# almost all ok --> see how long it can take to reimplement PCP --> I guess can be quite fast indeed
|
|
1799
|
+
|
|
1800
|
+
#
|
|
1801
|
+
|
|
1802
|
+
# try also triangulation and compute 3D area in fact using height map --> need be sure the centroid is in the cell
|
|
1803
|
+
|
|
1804
|
+
# print('real cell area', cell.area + reg[idx].perimeter / 2)
|
|
1805
|
+
|
|
1806
|
+
# qsdqsqsd
|
|
1807
|
+
# almost ok but then would need the vertices and the bonds --> see how to do
|
|
1808
|
+
# for bonds I have the perfect algo juts need to add pairs of vertices
|
|
1809
|
+
# and this does not require sorting bonds
|
|
1810
|
+
|
|
1811
|
+
# place back on orig image --> easy if one dilation --> bbox -1 and +1 for all dims
|
|
1812
|
+
|
|
1813
|
+
#
|
|
1814
|
+
# plt.imshow(dilated_mask) # seems ok then just need merge with the original mask and I'll have what I need
|
|
1815
|
+
# plt.show()
|
|
1816
|
+
#
|
|
1817
|
+
|
|
1818
|
+
# plt.imshow(lab_perim)
|
|
1819
|
+
# plt.show()
|
|
1820
|
+
|
|
1821
|
+
# is there a bug
|
|
1822
|
+
|
|
1823
|
+
# that's very good but I just miss vertices at the border from this image --> rescue them maybe, see if with no border that works or not ???
|
|
1824
|
+
|
|
1825
|
+
# the funny thing is this code labels all the vertices --> except at the border --> that is very funny in fact and also labels bonds --> really cool in fact I love it
|
|
1826
|
+
# en fait si les vertices at the border sont labeles par des 1 une foir fini
|
|
1827
|
+
|
|
1828
|
+
# DO I NEED THAT ???? --> try nactivate this line then all ok !!!
|
|
1829
|
+
cells[bbox[0] - 1:bbox[2] + 1, bbox[1] - 1: bbox[3] + 1] += dilated_mask.astype(np.uint8)
|
|
1830
|
+
# cells[bbox[0]-1:bbox[2]+1, bbox[1]-1: bbox[3]+1] = cell.label+1
|
|
1831
|
+
|
|
1832
|
+
# place back the mask on original maybe for quantification such as intensity --> TODO
|
|
1833
|
+
|
|
1834
|
+
# seems like the perimeter is in fact what I want in 2D at least: Perimeter of object which approximates the contour as a line through the centers of border pixels using a 4-connectivity.
|
|
1835
|
+
|
|
1836
|
+
# probably not good in fact
|
|
1837
|
+
|
|
1838
|
+
# break
|
|
1839
|
+
|
|
1840
|
+
# again we save all the data in the very end so that if anything goes wrong the stuff is not added at all
|
|
1841
|
+
# in fact that trick may be a super code to label all the cells and all the bonds of it --> really cool in fact -->think about it and how to integrate it some day, almost there though
|
|
1842
|
+
cells_2D['local_ID'].append(cell.label)
|
|
1843
|
+
if cell.label in border_cells:
|
|
1844
|
+
cells_2D['is_border'].append(
|
|
1845
|
+
1) # somehow there is a bug here because it is saved as a text and I wanted to have it as a boolean --> no clue why
|
|
1846
|
+
else:
|
|
1847
|
+
cells_2D['is_border'].append(0)
|
|
1848
|
+
# this is very slow --> is there no better way ??
|
|
1849
|
+
if cell.label in border_cells_plus_one: # TODO
|
|
1850
|
+
cells_2D['is_border_plus_one'].append(
|
|
1851
|
+
1) # somehow there is a bug here because it is saved as a text and I wanted to have it as a boolean --> no clue why
|
|
1852
|
+
else:
|
|
1853
|
+
cells_2D['is_border_plus_one'].append(0)
|
|
1854
|
+
cells_2D['bond_cut_off'].append(bond_cut_off)
|
|
1855
|
+
cells_3D['local_ID'].append(cell.label)
|
|
1856
|
+
cells_2D['pixel_within_cell_y'].append(point_awlays_inside_the_cell[0])
|
|
1857
|
+
cells_2D['pixel_within_cell_x'].append(point_awlays_inside_the_cell[1])
|
|
1858
|
+
cells_2D['first_pixel_y'].append(cell.coords[0][0])
|
|
1859
|
+
cells_2D['first_pixel_x'].append(cell.coords[0][1])
|
|
1860
|
+
cells_2D['cytoplasmic_area'].append(cell.area)
|
|
1861
|
+
# print('centroid', cell.centroid)
|
|
1862
|
+
centroid = cell.centroid
|
|
1863
|
+
# if len(centroid)==3:
|
|
1864
|
+
# cells_3D['centroid_z']=centroid[0] # impossible cause 2D
|
|
1865
|
+
# image is 2D
|
|
1866
|
+
cells_2D['centroid_y'].append(centroid[-2])
|
|
1867
|
+
cells_2D['centroid_x'].append(centroid[-1])
|
|
1868
|
+
|
|
1869
|
+
cells_2D['perimeter'].append(reg[idx].perimeter)# nb maybe this value is incorrect because it's an apporximation --> probably I should replace it even if it will be much slower
|
|
1870
|
+
cells_2D['perimeter_pixel_count'].append(reg[idx].area)
|
|
1871
|
+
cells_2D['area'].append(cell.area + reg[idx].perimeter / 2.) # NB should I do that in 3D too???
|
|
1872
|
+
|
|
1873
|
+
# scipy elongation and orientation of cells --> TODO --> maybe also add the TA one just for compatibility
|
|
1874
|
+
# cells_2D['major_axis_length'].append(cell.major_axis_length)
|
|
1875
|
+
# cells_2D['minor_axis_length'].append(cell.minor_axis_length)
|
|
1876
|
+
|
|
1877
|
+
try:
|
|
1878
|
+
# stretch is slow --> so maybe offer this as an option ???
|
|
1879
|
+
stretch_nematic = compute_stretch_nematic(cell)
|
|
1880
|
+
cells_2D['orientation'].append(stretch_nematic.get_angle2())
|
|
1881
|
+
# cells_2D['eccentricity'].append(cell.eccentricity)
|
|
1882
|
+
cells_2D['elongation'].append(stretch_nematic.getS0())
|
|
1883
|
+
cells_2D['S1'].append(stretch_nematic.S1)
|
|
1884
|
+
cells_2D['S2'].append(stretch_nematic.S2)
|
|
1885
|
+
except:
|
|
1886
|
+
# if True:
|
|
1887
|
+
# traceback.print_exc()
|
|
1888
|
+
cells_2D['orientation'].append(None)
|
|
1889
|
+
# cells_2D['eccentricity'].append(cell.eccentricity)
|
|
1890
|
+
cells_2D['elongation'].append(None)
|
|
1891
|
+
cells_2D['S1'] .append( None)
|
|
1892
|
+
cells_2D['S2'].append( None)
|
|
1893
|
+
|
|
1894
|
+
|
|
1895
|
+
# sqsqdsq
|
|
1896
|
+
|
|
1897
|
+
if measure_polarity:
|
|
1898
|
+
# print('polarity nematic', polarity_nematic) # TODO DO THIS FOR ALL CHANNELS
|
|
1899
|
+
for ppp in range(len(polarity_nematic) - 1):
|
|
1900
|
+
if isinstance(polarity_nematic[0], list):
|
|
1901
|
+
for ccc in range(len(polarity_nematic[0])):
|
|
1902
|
+
# print('TODO sum_bd_intensity,avg_bd_intensity', sum_bd_intensity[ccc], avg_bd_intensity[ccc])
|
|
1903
|
+
if 'Q' + str(ppp + 1) + '_polarity_ch' + str(ccc) not in cells_2D:
|
|
1904
|
+
cells_2D['Q' + str(ppp + 1) + '_polarity_ch' + str(ccc)] = []
|
|
1905
|
+
cells_2D['normalized_Q' + str(ppp + 1) + '_polarity_ch' + str(ccc)] = []
|
|
1906
|
+
cells_2D['Q' + str(ppp + 1) + '_polarity_ch' + str(ccc)].append(polarity_nematic[ppp][ccc])
|
|
1907
|
+
try:
|
|
1908
|
+
cells_2D['normalized_Q' + str(ppp + 1) + '_polarity_ch' + str(ccc)].append(
|
|
1909
|
+
polarity_nematic[ppp][ccc] / polarity_nematic[-1][ccc])
|
|
1910
|
+
except:
|
|
1911
|
+
# error division by 0 --> set it to 0
|
|
1912
|
+
cells_2D['normalized_Q' + str(ppp + 1) + '_polarity_ch' + str(ccc)].append(0.)
|
|
1913
|
+
else:
|
|
1914
|
+
if 'Q' + str(ppp + 1) + '_polarity_ch' + str(0) not in cells_2D:
|
|
1915
|
+
cells_2D['Q' + str(ppp + 1) + '_polarity_ch' + str(0)] = []
|
|
1916
|
+
cells_2D['normalized_Q' + str(ppp + 1) + '_polarity_ch' + str(0)] = []
|
|
1917
|
+
cells_2D['Q' + str(ppp + 1) + '_polarity_ch' + str(0)].append(polarity_nematic[ppp])
|
|
1918
|
+
try:
|
|
1919
|
+
cells_2D['normalized_Q' + str(ppp + 1) + '_polarity_ch' + str(0)].append(
|
|
1920
|
+
polarity_nematic[ppp] / polarity_nematic[-1])
|
|
1921
|
+
except:
|
|
1922
|
+
# error division by 0 --> set it to 0
|
|
1923
|
+
cells_2D['normalized_Q' + str(ppp + 1) + '_polarity_ch' + str(0)].append(0.)
|
|
1924
|
+
|
|
1925
|
+
# qssqsqqssqsqsqdsqdsqd
|
|
1926
|
+
# print(type(polarity_nematic[0])) # --> why is it an image ???
|
|
1927
|
+
# plot the intensities too!!!
|
|
1928
|
+
# plot cytoplasmic intensity
|
|
1929
|
+
# plot cortical intensity
|
|
1930
|
+
# plot nematics and I'll be done...
|
|
1931
|
+
|
|
1932
|
+
# store all the cell vertices ids
|
|
1933
|
+
|
|
1934
|
+
cells_2D['vertices'].append(vx_local_ids) # TODO shall I add bonds --> also need create a vertices table
|
|
1935
|
+
cells_2D['nb_of_vertices_or_neighbours'].append(len(vx_local_ids))
|
|
1936
|
+
# nb_of_vertices_or_neighbours_cut_off = len(vx_local_ids)
|
|
1937
|
+
|
|
1938
|
+
bond_length_of_the_cell = bond_lengths_associated_to_a_given_cell[cell.label]
|
|
1939
|
+
nb_of_vertices_or_neighbours_cut_off = len(bond_length_of_the_cell)
|
|
1940
|
+
if bond_cut_off is not None and bond_cut_off > 0:
|
|
1941
|
+
bond_length_of_the_cell = [bdl for bdl in bond_length_of_the_cell if bdl > bond_cut_off]
|
|
1942
|
+
nb_of_vertices_or_neighbours_cut_off = len(bond_length_of_the_cell)
|
|
1943
|
+
# del bond_lengths_associated_to_a_given_cell[cell.label]
|
|
1944
|
+
cells_2D['nb_of_vertices_or_neighbours_cut_off'].append(nb_of_vertices_or_neighbours_cut_off)
|
|
1945
|
+
bonds_of_cll = bonds_associated_to_a_given_cell[cell.label]
|
|
1946
|
+
cells_2D['bonds'].append(bonds_of_cll)
|
|
1947
|
+
|
|
1948
|
+
if measure_3D and height_map is not None:
|
|
1949
|
+
cells_3D['area3D'].append(area3D)
|
|
1950
|
+
cells_3D['area_flat_height'].append(area3D_flat_3D)
|
|
1951
|
+
cells_3D['perimeter3D'].append(perimeter3D)
|
|
1952
|
+
|
|
1953
|
+
# print('cytoplasmic area',cell.area) # area is the area without the perimeter, see how the perim is computed --> same as in IJ
|
|
1954
|
+
|
|
1955
|
+
if __DEBUG__:
|
|
1956
|
+
print('debug #17')
|
|
1957
|
+
# cells[vertices==255]=6
|
|
1958
|
+
|
|
1959
|
+
# plt.imshow(cells)
|
|
1960
|
+
# plt.show()
|
|
1961
|
+
|
|
1962
|
+
# Img(lab_cells).save('/E/Sample_images/sample_images_PA/mini/focused_Series012/0_test_IJ_perimeter.tif')
|
|
1963
|
+
|
|
1964
|
+
# all is ok I may just need to get bonds and their perimeter now etc and do also 3D measurements --> in same or in new table --> think about it
|
|
1965
|
+
# almost there and almost have a TA that is even working better than original and much simpler to code and maintain
|
|
1966
|
+
|
|
1967
|
+
# need get bonds and measure them --> should be easy in fact
|
|
1968
|
+
# get the bonds, fill them and get their 2D perimeter then find their associated vertices and create the final version of the bond and measure its length --> not so hard then can give it an id --> TODO
|
|
1969
|
+
|
|
1970
|
+
# skimage.measure.perimeter(image, neighbourhood=4)
|
|
1971
|
+
|
|
1972
|
+
# finally just need get now the pairs of vertices and add them to bonds
|
|
1973
|
+
# maybe also smart to measure average intensity
|
|
1974
|
+
|
|
1975
|
+
# detect vertex pairs
|
|
1976
|
+
# --> just detect them and pair them maybe --> TODO
|
|
1977
|
+
# see the most efficient way to do that
|
|
1978
|
+
|
|
1979
|
+
# vertices_coords = np.where(vertices==255)
|
|
1980
|
+
#
|
|
1981
|
+
#
|
|
1982
|
+
# # print(vertices_coords)
|
|
1983
|
+
# for vvv in range(len(vertices_coords[0])):
|
|
1984
|
+
# y = vertices_coords[0][vvv]
|
|
1985
|
+
# x = vertices_coords[1][vvv]
|
|
1986
|
+
#
|
|
1987
|
+
# print(y,x)
|
|
1988
|
+
# # get its neighbors in a safe way
|
|
1989
|
+
# for iii in range[-1,2,1]:
|
|
1990
|
+
# for jjj in range[-1,2,1]:
|
|
1991
|
+
# if vertices[]
|
|
1992
|
+
|
|
1993
|
+
# easiest way is to flood the vertices and get those with area >= 2 --> a piece of cake TODO
|
|
1994
|
+
|
|
1995
|
+
# TODO REALLY NEED ADD THAT TOO
|
|
1996
|
+
# I need add this to bonds 2D and remove missing ones
|
|
1997
|
+
|
|
1998
|
+
# in fact that is easy I need add the stuff to the cell only in the very end
|
|
1999
|
+
# cells_2D['nb_of_vertices_or_neighbours_cut_off'].append(nb_of_vertices_or_neighbours_cut_off)
|
|
2000
|
+
|
|
2001
|
+
# en fait marche pas --> see how I can do that
|
|
2002
|
+
|
|
2003
|
+
# all is ok
|
|
2004
|
+
# print(pairs_of_vertices)
|
|
2005
|
+
# print(len(pairs_of_vertices)) # -->18
|
|
2006
|
+
# print(len(pairs_of_vertices[0])) # -->2
|
|
2007
|
+
|
|
2008
|
+
# final thing that must be done is the polarity --> but it requires sorting vertices and so will be slow --> do not do it by default
|
|
2009
|
+
|
|
2010
|
+
# these can also be considered as fourway vertices in the same way as bonds below a cutoff --> I could do that and save those
|
|
2011
|
+
# shall I store local vx id too
|
|
2012
|
+
|
|
2013
|
+
# almost all is saved and finally I need also do things in 3D --> not that hard by the way and can be done if I have the height map --> enable it by default if height map is there
|
|
2014
|
+
# just need triangulate all the cells
|
|
2015
|
+
# maybe offer control of the nb of CPUs to use at startup or in settings and try to MT things --> probably not hard and can be done at the level of the list --> should not be too hard
|
|
2016
|
+
# need also count the nb of vertices per cell to get nb of neighbours and need get
|
|
2017
|
+
# need create a viewer and something that can export to IJ from the command line --> à tester en fait mais devrait pas etre trop dur je pense et je peux facilement generer des stacks on demand --> TODO
|
|
2018
|
+
|
|
2019
|
+
# do all of that and get rid of TA
|
|
2020
|
+
|
|
2021
|
+
# try to really finalize something
|
|
2022
|
+
# see how much memory I would need in the end for that
|
|
2023
|
+
# do a nematic class and allow it to be plotted
|
|
2024
|
+
|
|
2025
|
+
# see how much time it would take just for one case of one big image ????
|
|
2026
|
+
# do the parallelization
|
|
2027
|
+
# finalize tracking error correction --> TODO
|
|
2028
|
+
# then try to finalize a GUI, and really clean all too
|
|
2029
|
+
# try speed up also labels by having it to compute just the really necessary things...
|
|
2030
|
+
|
|
2031
|
+
# print('bonds_associated_to_a_given_cell',bonds_associated_to_a_given_cell)
|
|
2032
|
+
# print('bond_lengths_associated_to_a_given_cell',bond_lengths_associated_to_a_given_cell)
|
|
2033
|
+
|
|
2034
|
+
if __DEBUG__:
|
|
2035
|
+
print('debug #18')
|
|
2036
|
+
if TA_path is not None:
|
|
2037
|
+
db = TAsql(db_path)
|
|
2038
|
+
# print('cells_2D'*20)
|
|
2039
|
+
db.create_and_append_table(table_name='vertices_2D', datas=fill_missing_with_Nones(vertices_2D))
|
|
2040
|
+
db.create_and_append_table(table_name='cells_2D', datas=fill_missing_with_Nones(cells_2D))
|
|
2041
|
+
# print('cells_3D'*20)
|
|
2042
|
+
# print('bonds_2D' * 20)
|
|
2043
|
+
db.create_and_append_table(table_name='bonds_2D', datas=fill_missing_with_Nones(bonds_2D))
|
|
2044
|
+
if measure_3D and height_map is not None:
|
|
2045
|
+
db.create_and_append_table(table_name='cells_3D', datas=fill_missing_with_Nones(cells_3D))
|
|
2046
|
+
db.create_and_append_table(table_name='bonds_3D', datas=fill_missing_with_Nones(bonds_3D))
|
|
2047
|
+
elif measure_3D and height_map is None:
|
|
2048
|
+
db.drop_table('cells_3D')
|
|
2049
|
+
db.drop_table('bonds_3D')
|
|
2050
|
+
|
|
2051
|
+
db.close()
|
|
2052
|
+
else:
|
|
2053
|
+
# plt.imshow(cells)
|
|
2054
|
+
# plt.show()
|
|
2055
|
+
# maybe return an error and always close the db
|
|
2056
|
+
|
|
2057
|
+
print('cells_2D', cells_2D)
|
|
2058
|
+
print('cells_3D', cells_3D)
|
|
2059
|
+
print('bonds_2D', bonds_2D)
|
|
2060
|
+
print('bonds_3D', bonds_3D)
|
|
2061
|
+
print('vertices_2D', vertices_2D)
|
|
2062
|
+
|
|
2063
|
+
for k, v in cells_2D.items():
|
|
2064
|
+
print(len(v))
|
|
2065
|
+
|
|
2066
|
+
cells_2D = fill_missing_with_Nones(cells_2D)
|
|
2067
|
+
print('#' * 20)
|
|
2068
|
+
for k, v in cells_2D.items():
|
|
2069
|
+
print(len(v))
|
|
2070
|
+
|
|
2071
|
+
if __DEBUG__:
|
|
2072
|
+
print('debug #19')
|
|
2073
|
+
print('total time', timer() - start)
|
|
2074
|
+
|
|
2075
|
+
# do it a class and make it modular so that the minimal nb of things are executed
|
|
2076
|
+
|
|
2077
|
+
# je pense 4-5 secs par image sans trier les contours --> not super slow but also not very fast
|
|
2078
|
+
# speed up computation of contour by using numpy array --> remember my distance code
|
|
2079
|
+
|
|
2080
|
+
# should all be fast to do --> 3-4 days I think
|
|
2081
|
+
|
|
2082
|
+
# see what's missing
|
|
2083
|
+
# 2.3 secs per stuff --> not bad, in fact maybe as fast as TA now
|
|
2084
|
+
# need sort contour
|
|
2085
|
+
# need get bonds and their vertices --> TODO
|
|
2086
|
+
# need all other parameters
|
|
2087
|
+
# if scaling parameter then one needs to specify
|
|
2088
|
+
# need scaling factors if heightmap is there
|
|
2089
|
+
|
|
2090
|
+
# finalize everything and maybe retrain a model that already works very well for the projection
|
|
2091
|
+
|
|
2092
|
+
# TODO do the db part
|
|
2093
|
+
# also do the sorting part
|
|
2094
|
+
|
|
2095
|
+
# and also I need to do the intensity part --> TODO
|
|
2096
|
+
# also make it a class that is easy to use
|
|
2097
|
+
|
|
2098
|
+
# also do the triangulation part for 3D --> should not be too hard to do
|
|
2099
|
+
|
|
2100
|
+
|
|
2101
|
+
if __name__ == '__main__':
|
|
2102
|
+
from datetime import datetime
|
|
2103
|
+
print(datetime.now())
|
|
2104
|
+
|
|
2105
|
+
|
|
2106
|
+
if False:
|
|
2107
|
+
print(round(5.59)) # not good
|
|
2108
|
+
print(round(5.39)) # not good
|
|
2109
|
+
import sys
|
|
2110
|
+
|
|
2111
|
+
sys.exit(0)
|
|
2112
|
+
|
|
2113
|
+
if False:
|
|
2114
|
+
# original_image = Img('/E/Sample_images/sample_images_PA/mini/focused_Series012/handCorrection.png')[..., 1] # if no shift max and min should always be 255 otherwise there is an error somewhere
|
|
2115
|
+
original_image = Img('/E/Sample_images/sample_images_PA/mini/focused_Series012.png')[
|
|
2116
|
+
..., 1] # if no shift max and min should always be 255 otherwise there is an error somewhere
|
|
2117
|
+
# cells = Img('/E/Sample_images/sample_images_PA/mini/focused_Series012/handCorrection.png')[..., 0]
|
|
2118
|
+
cells = Img('/E/Sample_images/sample_images_PA/mini/focused_Series012/handCorrection.tif')
|
|
2119
|
+
# height_map = None # Img('/E/Sample_images/sample_images_PA/mini/focused_Series012.png')[..., 1]
|
|
2120
|
+
height_map = Img('/E/Sample_images/sample_images_PA/mini/focused_Series012.png')[..., 1]
|
|
2121
|
+
# height_map = Img('/E/Sample_images/sample_images_PA/mini/focused_Series012.png')[..., 0] # another good test because all is 0 there --> marche car aire est proche de l'aire 2D par contre pr handcorrection ça marche pas car tres different de l'aire 2D --> see why and how to fix it
|
|
2122
|
+
# height_map = Img('/E/Sample_images/sample_images_PA/mini/focused_Series012/handCorrection.png')[..., 0] # good for a test as all heights are the same... --> in fact that makes sense since some heigts are 0 and some are 255 since the centroid of the polygon is always 0
|
|
2123
|
+
|
|
2124
|
+
# for manual debug KEEP:
|
|
2125
|
+
# TAMeasurements(None,__forced_orig=original_image, __forced_cells=cells, __forced_heightmap=height_map)
|
|
2126
|
+
|
|
2127
|
+
# TAMeasurements(None, __forced_orig=original_image, __forced_cells=cells, __forced_heightmap=height_map,measure_polarity=True, measure_3D=True)
|
|
2128
|
+
# import sys
|
|
2129
|
+
# sys.exit(0)
|
|
2130
|
+
|
|
2131
|
+
# make it loop add nb of neighbors à la TA with cut off and also add support for lists of files--> in the same self loop by the way --> no waste of time this way and add support for progress
|
|
2132
|
+
|
|
2133
|
+
# TAMeasurements('/E/Sample_images/sample_images_PA/mini/focused_Series012.png', measure_polarity=True, measure_3D=True) # --> almost there just need create one db per file now!!!
|
|
2134
|
+
# TAMeasurements('/E/Sample_images/sample_images_PA/mini_different_nb_of_channels/focused_Series012.png', measure_polarity=True, measure_3D=True) # --> almost there just need create one db per file now!!!
|
|
2135
|
+
# TAMeasurements(loadlist('/E/Sample_images/sample_images_PA/mini_different_nb_of_channels/list.lst'),measure_polarity=True, measure_3D=True) # --> almost there just need create one db per file now!!!
|
|
2136
|
+
# TAMeasurements(['/E/Sample_images/sample_images_pyta/surface_projection/210219.lif_t000.tif'], measure_polarity=True, measure_3D=True) # --> almost there just need create one db per file now!!!
|
|
2137
|
+
# TAMeasurements(['/E/Sample_images/sample_images_pyta/surface_projection/exposures_1_P04.tif'],measure_polarity=True, measure_3D=True) # --> almost there just need create one db per file now!!!
|
|
2138
|
+
# TAMeasurements(loadlist('/E/Sample_images/sample_images_pyta/surface_projection/list.lst'),measure_polarity=True, measure_3D=True) # --> almost there just need create one db per file now!!!
|
|
2139
|
+
# TAMeasurements(loadlist('/E/Sample_images/sample_images_pyta/surface_projection/list.lst'),measure_polarity=False, measure_3D=False) # causes a bug --> try see why ????
|
|
2140
|
+
# TAMeasurements(['/E/Sample_images/sample_images_PA/mini_different_nb_of_channels/mini_focused_Series014_for_debug_polarity_nematic.tif'], measure_polarity=True,measure_3D=True) # --> almost there just need create one db per file now!!!
|
|
2141
|
+
|
|
2142
|
+
# test with list
|
|
2143
|
+
TAMeasurements(['/E/Sample_images/sample_images_PA/mini/focused_Series012.png','/E/Sample_images/sample_images_PA/mini/focused_Series014.png'], measure_polarity=False, measure_3D=False) # --> almost there just need create one db per file now!!!
|
|
2144
|
+
|
|
2145
|
+
|
|
2146
|
+
# /E/Sample_images/sample_images_pyta/surface_projection/list.lst
|
|
2147
|
+
|
|
2148
|
+
# TODO make it also save the vertices, cells and bonds ??? --> easy TODO in fact
|
|
2149
|
+
import sys
|
|
2150
|
+
sys.exit(0)
|
|
2151
|
+
|
|
2152
|
+
if True:
|
|
2153
|
+
start = timer()
|
|
2154
|
+
merge_names = loadlist('/E/Sample_images/sample_images_PA/mini_vide/list_simple.lst')
|
|
2155
|
+
# TAMeasurements(merge_names, measure_polarity=False, measure_3D=False, multi_threading=False)
|
|
2156
|
+
TAMeasurements(merge_names, measure_polarity=False, measure_3D=False, multi_threading=True) # vrai gain mais pas sur mac... comprend rien quand meme --> est ce du à numba
|
|
2157
|
+
print('total execution time', timer() - start)
|
|
2158
|
+
|
|
2159
|
+
import sys
|
|
2160
|
+
sys.exit(0)
|
|
2161
|
+
|
|
2162
|
+
# if False:
|
|
2163
|
+
# # failed attempt to launch it in a thread
|
|
2164
|
+
#
|
|
2165
|
+
# start = timer()
|
|
2166
|
+
# # try MT the finish all
|
|
2167
|
+
# # import multiprocessing
|
|
2168
|
+
# # merge_names = ['/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']
|
|
2169
|
+
# # TRY MY THE MeA
|
|
2170
|
+
# # pas mal mais il me faudrait une progress bar en fait
|
|
2171
|
+
# # with multiprocessing.Pool(processes=8) as pool:
|
|
2172
|
+
# # results = pool.map(TAMeasurements, merge_names)
|
|
2173
|
+
#
|
|
2174
|
+
# # merge_names = loadlist('/E/Sample_images/trash/complete/liste.lst')
|
|
2175
|
+
# # merge_names = loadlist('/E/Sample_images/sample_images_denoise_manue/211029_EcadKI_mel_40-54hAPF_ON/surface_projection/list.lst')
|
|
2176
|
+
# merge_names = loadlist('/E/Sample_images/sample_images_PA/mini_vide/list_simple.lst')
|
|
2177
|
+
#
|
|
2178
|
+
# from functools import partial
|
|
2179
|
+
# from epyseg.ta.pyqt_test_threads_instead_of_threadpool import Worker2
|
|
2180
|
+
#
|
|
2181
|
+
# func = partial(TAMeasurements)
|
|
2182
|
+
# thread = Worker2(func, merge_names, measure_polarity=False, measure_3D=False)
|
|
2183
|
+
#
|
|
2184
|
+
# # self.thread.result.connect(self.print_output)
|
|
2185
|
+
# # self.thread.finished.connect(self.thread_complete)
|
|
2186
|
+
# # this is specific of this method I must update the nb of inputs and outputs of the model # be CAREFUL IF COPYING THIS CODE THE FOLLOWING MUST BE REMOVED
|
|
2187
|
+
# # worker.signals.finished.connect(self._set_model_inputs_and_outputs)
|
|
2188
|
+
# # self.thread.progress.connect(self.progress_fn)
|
|
2189
|
+
# thread.setTerminationEnabled(True)
|
|
2190
|
+
#
|
|
2191
|
+
# # Execute
|
|
2192
|
+
# # if isinstance(self.thread, FakeWorker2):
|
|
2193
|
+
# # # no threading
|
|
2194
|
+
# # self.thread.run()
|
|
2195
|
+
# # else:
|
|
2196
|
+
# # threading
|
|
2197
|
+
# # self.threadpool.start(worker)
|
|
2198
|
+
# # self.threads.append(worker)
|
|
2199
|
+
# # worker.moveToThread(self.thread)
|
|
2200
|
+
#
|
|
2201
|
+
# # self.thread.started.connect(self.thread.run)
|
|
2202
|
+
# thread.start()
|
|
2203
|
+
#
|
|
2204
|
+
# # NON MT --> 1400secs
|
|
2205
|
+
#
|
|
2206
|
+
# # marche mais pas qd lancé depuis pyqt --> why -> can I simulate launch in a thread ????
|
|
2207
|
+
#
|
|
2208
|
+
# # MT --> 176secs --> really worth it!!!
|
|
2209
|
+
# # from tqdm import tqdm
|
|
2210
|
+
# # import sys
|
|
2211
|
+
# # pool = Pool(processes=15)
|
|
2212
|
+
# # for i, _ in enumerate(tqdm(pool.imap_unordered(TAMeasurements, merge_names), total=len(merge_names))):
|
|
2213
|
+
# # # pass
|
|
2214
|
+
# # # sys.stderr.write('\rdone {0:%}'.format(i / len(merge_names))) # --> I could use that to plot with the other progressbar --> ok
|
|
2215
|
+
# # # cool --> I can use that to display progress in the other progress bar --> the QT one
|
|
2216
|
+
# # pass
|
|
2217
|
+
# #
|
|
2218
|
+
# # pool.close()
|
|
2219
|
+
# # pool.join()
|
|
2220
|
+
#
|
|
2221
|
+
# print('total execution time', timer() - start)
|
|
2222
|
+
# # import sys
|
|
2223
|
+
# # sys.exit(0)
|
|
2224
|
+
#
|
|
2225
|
+
# # why not running ???
|
|
2226
|
+
|