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
|
File without changes
|
|
File without changes
|
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
# https://gis.stackexchange.com/questions/76498/how-is-st-pointonsurface-calculated # really great and what I'm looking for
|
|
2
|
+
# https://geocompr.robinlovelace.net/geometric-operations.html#centroids
|
|
3
|
+
|
|
4
|
+
# this sounds like a smart and nice method --> see how fast this is to implement that
|
|
5
|
+
|
|
6
|
+
# can I do a fast version of it that relies on vertices to find this point
|
|
7
|
+
# scan line by line the shape maybe using bounding box and take the center of the longest continuous line as the centroid --> maybe that is a really good idea
|
|
8
|
+
|
|
9
|
+
# the following code is based on the idea described here https://gis.stackexchange.com/questions/76498/how-is-st-pointonsurface-calculated
|
|
10
|
+
from math import ceil
|
|
11
|
+
|
|
12
|
+
import numpy as np
|
|
13
|
+
from skimage.measure._regionprops import RegionProperties
|
|
14
|
+
|
|
15
|
+
from batoolset.img import Img
|
|
16
|
+
import matplotlib.pyplot as plt
|
|
17
|
+
from skimage.measure import regionprops
|
|
18
|
+
from skimage import measure
|
|
19
|
+
from skimage.draw import disk
|
|
20
|
+
from timeit import default_timer as timer
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
# that seems to work but do some cleaning and the only issue is that if cell is too close to border, such as a fake cell surrounding the image then it will be the first line --> and it would be easy
|
|
24
|
+
|
|
25
|
+
# TODO also always use that for tracking as this should be much better than things I was using before and should prevent issues
|
|
26
|
+
__DEBUG__ = False
|
|
27
|
+
|
|
28
|
+
def point_on_surface2(region, labels, prefer_centroid_if_inside_the_cell=True):
|
|
29
|
+
# new version of point_on_surface just coded to be more flexible, code is not the same and behaviour may differ --> compare thoroughly some day
|
|
30
|
+
if isinstance(region, RegionProperties):
|
|
31
|
+
region =region.coords
|
|
32
|
+
cell_id = labels[region[0][0], region[0][1]]
|
|
33
|
+
centroid = np.rint(np.average(region, axis=0)).astype(int)
|
|
34
|
+
if prefer_centroid_if_inside_the_cell and labels[centroid[0], centroid[1]] == cell_id:
|
|
35
|
+
return centroid
|
|
36
|
+
else:
|
|
37
|
+
# TODO FIX THAT SOME DAY lazy way of doing just return the first pixel of the shape maybe some centroid like would be better but ok for wings and for what I wanna do --> MAYBE TAKE CODE IN ORIGINAL FUNCTION AND HACK IT TO WORK WITH NDARRAYS
|
|
38
|
+
return region[0]
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
# TODO clean code
|
|
43
|
+
# this point will by definition always be inside the cell even in concave shapes
|
|
44
|
+
|
|
45
|
+
# the other possibility is the ultimate erosion but this will be extremely slow and resource consuming; I guess
|
|
46
|
+
# inspired by https://gis.stackexchange.com/questions/76498/how-is-st-pointonsurface-calculated but then I deviated from it
|
|
47
|
+
def point_on_surface(region, labels, prefer_centroid_if_inside_the_cell=True):
|
|
48
|
+
# TODO --> maybe ceil the centroid to get a better centroid point (pb can be outside of the image although it is very unlikely (in fact it is not possible --> can ceil)
|
|
49
|
+
|
|
50
|
+
cell_id = labels[region.coords[0][0], region.coords[0][1]]
|
|
51
|
+
|
|
52
|
+
if prefer_centroid_if_inside_the_cell:
|
|
53
|
+
centroid = region.centroid
|
|
54
|
+
|
|
55
|
+
# TODO replace by rounding maybe some day but ok for now
|
|
56
|
+
|
|
57
|
+
# if labels[int(ceil(centroid[0])), int(ceil(centroid[1]))]==cell_id:
|
|
58
|
+
# return (int(ceil(centroid[0])), int(ceil(centroid[1])))
|
|
59
|
+
if labels[int(round(centroid[0])), int(round(centroid[1]))]==cell_id:
|
|
60
|
+
return (int(round(centroid[0])), int(round(centroid[1])))
|
|
61
|
+
|
|
62
|
+
if __DEBUG__:
|
|
63
|
+
print(cell_id)
|
|
64
|
+
|
|
65
|
+
max_line_length = 0
|
|
66
|
+
# line_length_counter = 0
|
|
67
|
+
point_on_surface = (region.coords[0][0], region.coords[0][1])
|
|
68
|
+
|
|
69
|
+
# how do I get the
|
|
70
|
+
# get the centroid of the region
|
|
71
|
+
# --> ended ok
|
|
72
|
+
cell_encountered = False
|
|
73
|
+
first_encounter_x = None
|
|
74
|
+
line_length_counter = 0
|
|
75
|
+
# there is a bug
|
|
76
|
+
|
|
77
|
+
for iii in range(region.bbox[0], region.bbox[2]):
|
|
78
|
+
# start_coord_x = region.bbox[1]
|
|
79
|
+
# end_coord_x = region.bbox[3]
|
|
80
|
+
# if line_by_line:
|
|
81
|
+
cell_encountered = False
|
|
82
|
+
first_encounter_x = None
|
|
83
|
+
line_length_counter=0 # if I don't do set it to 0 here, I'll get some sort of center of mass effect which is maybe desired or not but if I do that this is very different from the idea above maybe ask for mode 1 or 2
|
|
84
|
+
for jjj in range(region.bbox[1], region.bbox[3]):
|
|
85
|
+
|
|
86
|
+
if labels[iii, jjj] == cell_id:
|
|
87
|
+
# print(cell_encountered, iii, jjj, line_length_counter)
|
|
88
|
+
if not cell_encountered:
|
|
89
|
+
if __DEBUG__:
|
|
90
|
+
print('first encounter', iii, jjj)
|
|
91
|
+
first_encounter_x = jjj
|
|
92
|
+
cell_encountered = True
|
|
93
|
+
line_length_counter += 1
|
|
94
|
+
# print('1',line_length_counter, first_encounter_x, jjj) # --> inded
|
|
95
|
+
else:
|
|
96
|
+
if __DEBUG__:
|
|
97
|
+
if line_length_counter>0:
|
|
98
|
+
print('last encounter', iii, jjj, line_length_counter)
|
|
99
|
+
if line_length_counter >= max_line_length and first_encounter_x is not None:
|
|
100
|
+
max_line_length = line_length_counter
|
|
101
|
+
point_on_surface = (
|
|
102
|
+
iii, int(first_encounter_x + (jjj - first_encounter_x) / 2)) # get the centroid of the line
|
|
103
|
+
if __DEBUG__:
|
|
104
|
+
print('2',region.bbox, max_line_length, point_on_surface, first_encounter_x, cell_encountered, iii, jjj)
|
|
105
|
+
|
|
106
|
+
first_encounter_x = None # reset first encounter
|
|
107
|
+
cell_encountered = False # reset first encounter
|
|
108
|
+
line_length_counter = 0
|
|
109
|
+
# else:
|
|
110
|
+
# line_length_counter = 0
|
|
111
|
+
# cell_encountered = False # reset first encounter
|
|
112
|
+
# first_encounter_x = None # reset first encounter
|
|
113
|
+
|
|
114
|
+
# if line_by_line:
|
|
115
|
+
# need reset also at the end of every loop if it has not found something
|
|
116
|
+
# nb replacing this by >= changes a bit the stuff --> that does make sense especially for cells at the border!!!
|
|
117
|
+
if line_length_counter > max_line_length and first_encounter_x is not None: # en fait c'est mieux comme ça
|
|
118
|
+
max_line_length = line_length_counter
|
|
119
|
+
point_on_surface = (
|
|
120
|
+
iii, int(first_encounter_x + (jjj - first_encounter_x) / 2)) # get the centroid of the line
|
|
121
|
+
if __DEBUG__:
|
|
122
|
+
print('2', region.bbox, max_line_length, point_on_surface, first_encounter_x, cell_encountered, iii, jjj)
|
|
123
|
+
|
|
124
|
+
|
|
125
|
+
# if line_length_counter > max_line_length and first_encounter_x is not None: # en fait c'est mieux comme ça
|
|
126
|
+
# max_line_length = line_length_counter
|
|
127
|
+
# point_on_surface = (
|
|
128
|
+
# iii, int(first_encounter_x + (jjj - first_encounter_x) / 2)) # get the centroid of the line
|
|
129
|
+
#
|
|
130
|
+
# if __DEBUG__:
|
|
131
|
+
# print('2', region.bbox, max_line_length, point_on_surface, first_encounter_x, cell_encountered, iii, jjj)
|
|
132
|
+
if __DEBUG__:
|
|
133
|
+
print(region.bbox)
|
|
134
|
+
return point_on_surface
|
|
135
|
+
|
|
136
|
+
if __name__ == '__main__':
|
|
137
|
+
|
|
138
|
+
start = timer()
|
|
139
|
+
|
|
140
|
+
# get a good test image here just to test the stuff
|
|
141
|
+
cells = \
|
|
142
|
+
Img('/E/Sample_images/sample_images_PA/trash_test_mem/full_wing_multi/early_stages/FocStich_RGB005/handCorrection.png')[
|
|
143
|
+
..., 0]
|
|
144
|
+
labels = measure.label(cells, connectivity=1, background=255) # FOUR_CONNECTED
|
|
145
|
+
# plt.imshow(labels)
|
|
146
|
+
# plt.show()
|
|
147
|
+
|
|
148
|
+
|
|
149
|
+
# c'est bon ça a l'air de bien marche en fait
|
|
150
|
+
for region in regionprops(labels):
|
|
151
|
+
if region.area > 60000:
|
|
152
|
+
# get its centroid
|
|
153
|
+
pt_on_surface = point_on_surface(region, labels)
|
|
154
|
+
print(pt_on_surface)
|
|
155
|
+
|
|
156
|
+
# compare computed position to the calculated position
|
|
157
|
+
centroid = region.centroid
|
|
158
|
+
x, y = disk(centroid, 30, shape=labels.shape)
|
|
159
|
+
# prefer centroid if inside
|
|
160
|
+
labels[x, y] = 30000
|
|
161
|
+
|
|
162
|
+
# labels[pt_on_surface[0], pt_on_surface[1]] = 6000
|
|
163
|
+
# for xx, yy in zip(x, y):
|
|
164
|
+
x, y = disk(pt_on_surface, 30, shape=labels.shape)
|
|
165
|
+
labels[x, y] = 25000
|
|
166
|
+
|
|
167
|
+
# ax.add_patch(circ)
|
|
168
|
+
|
|
169
|
+
# --> 5 secs --> not that bad I guess because the image is huge...
|
|
170
|
+
|
|
171
|
+
duration = timer() - start
|
|
172
|
+
print(duration)
|
|
173
|
+
|
|
174
|
+
plt.imshow(labels)
|
|
175
|
+
plt.show()
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
# the idea is to read the height map image and create a max proj out of it --> TODO
|
|
2
|
+
from batoolset.img import Img
|
|
3
|
+
import numpy as np
|
|
4
|
+
import matplotlib.pyplot as plt
|
|
5
|
+
|
|
6
|
+
def surface_projection_from_height_map(original_image, height_map , integer_mode = False, channel=None):
|
|
7
|
+
# to make it simple first just cast it
|
|
8
|
+
height_map_int = height_map.astype(np.uint8)
|
|
9
|
+
|
|
10
|
+
if channel is not None:
|
|
11
|
+
if len(original_image.shape)>2:
|
|
12
|
+
original_image = original_image[..., channel]
|
|
13
|
+
|
|
14
|
+
surface_projection = np.zeros_like(height_map)
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
# [os.path.join(path, f) for f in images_to_analyze if
|
|
18
|
+
# os.path.isfile(os.path.join(path, f))[]
|
|
19
|
+
# surface_projection = original_image[height_map,:,:]
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
min = height_map_int.min()
|
|
25
|
+
max = height_map_int.max()
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
for val in range(min, max):
|
|
29
|
+
surface_projection[height_map_int==val] = original_image[val, height_map_int==val]
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
# plt.imshow(difference_to_int)
|
|
36
|
+
# plt.show()
|
|
37
|
+
#
|
|
38
|
+
# plt.imshow(one_minus_difference)
|
|
39
|
+
# plt.show()
|
|
40
|
+
|
|
41
|
+
# plt.imshow(surface_projection)
|
|
42
|
+
# plt.show()
|
|
43
|
+
|
|
44
|
+
# Img(surface_projection,dimensions='hw').save('/E/Sample_images/sample_images_denoise_manue/trashme_test_robot/predict/surface_proj_int.tif')
|
|
45
|
+
|
|
46
|
+
if integer_mode:
|
|
47
|
+
return surface_projection
|
|
48
|
+
|
|
49
|
+
weights_for_layer_1 = height_map - height_map_int
|
|
50
|
+
weights_for_layer_0 = 1 - weights_for_layer_1
|
|
51
|
+
# NB try indexed_probs = np.take_along_axis(probs, np.expand_dims(indices, axis=-1), axis=-1)[..., 0]
|
|
52
|
+
|
|
53
|
+
for val in range(min, max-1):
|
|
54
|
+
layer_0 = original_image[val, height_map_int==val] * weights_for_layer_0[height_map_int == val]
|
|
55
|
+
layer_1 = original_image[val+1, height_map_int == val] * weights_for_layer_1[height_map_int == val]
|
|
56
|
+
# do weighted average of the layers --> TODO
|
|
57
|
+
# surface_projection[height_map_int == val] = (layer_0+layer_1)/2
|
|
58
|
+
# for each pixel I need to do the difference to the layer
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
# surface_projection[height_map_int == val] = (layer_0+layer_1)
|
|
62
|
+
surface_projection[height_map_int == val] = layer_0+layer_1
|
|
63
|
+
|
|
64
|
+
# pas mal mais voir comment gerer le fait que ce soit du float ???
|
|
65
|
+
|
|
66
|
+
# for floats get the rest and compute an average --> that is most likely not easy TODO --> that should be fairly easy todo in fact
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
# plt.imshow(surface_projection)
|
|
70
|
+
# plt.show()
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
# Img(surface_projection,dimensions='hw').save('/E/Sample_images/sample_images_denoise_manue/trashme_test_robot/predict/surface_proj_float.tif')
|
|
74
|
+
return surface_projection
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
if __name__ == '__main__':
|
|
78
|
+
height_map = Img('/E/Sample_images/sample_images_denoise_manue/trashme_test_robot/predict/Image7.tif')
|
|
79
|
+
original_image = Img('/E/Sample_images/sample_images_denoise_manue/trashme_test_robot/Image7.tif')
|
|
80
|
+
surface_proj = surface_projection_from_height_map(original_image, height_map)
|
|
81
|
+
plt.imshow(surface_proj)
|
|
82
|
+
plt.show()
|
|
@@ -0,0 +1,208 @@
|
|
|
1
|
+
import numpy as np
|
|
2
|
+
from batoolset.tools.logger import TA_logger # logging
|
|
3
|
+
from batoolset.ta.utils.rps_tools import pavlidis, compute_distance_between_consecutive_points
|
|
4
|
+
|
|
5
|
+
logger = TA_logger()
|
|
6
|
+
|
|
7
|
+
# this would actually work for 2D and 3D area --> heightmap is optional but it makes no sense to run this with 2D coords and no heightmaps
|
|
8
|
+
# if a heightmap is provided the z coords of every point will be replaced by height map height
|
|
9
|
+
# nb if several triangles are provided, it is assumed they are all traingulation of the same object, hence their area is summed and the sum is returned
|
|
10
|
+
def compute_3D_surfacearea(triangles, heightmap=None, stop_on_2D=False, disable_2D_warning=False):
|
|
11
|
+
"""
|
|
12
|
+
|
|
13
|
+
:param triangles: cell/object triangulation as input (as list or ndarray)
|
|
14
|
+
:param heightmap: a heightmap for the cell
|
|
15
|
+
:param stop_on_2D: break if 2D data is provided
|
|
16
|
+
:return: the surface area of the triangulated object
|
|
17
|
+
"""
|
|
18
|
+
if not isinstance(triangles, np.ndarray):
|
|
19
|
+
triangles = np.asarray(triangles)
|
|
20
|
+
|
|
21
|
+
if triangles.shape[-1] == 2 and heightmap is None:
|
|
22
|
+
if not disable_2D_warning:
|
|
23
|
+
logger.error(
|
|
24
|
+
'Error, triangle coords are purely 2D and no heightmap is provided, hence it is not possible to compute 3D area. To continue, the software will assume all heights are the same (= 0) (i.e. the image is really a pure 2D image)') # assuming 2D maybe --> just stack
|
|
25
|
+
|
|
26
|
+
if stop_on_2D:
|
|
27
|
+
return
|
|
28
|
+
|
|
29
|
+
flat_height = np.zeros((*triangles.shape[0:-1], (1)))
|
|
30
|
+
triangles = np.append(triangles, flat_height, -1)
|
|
31
|
+
|
|
32
|
+
# MEGA TODO NB SHOULD I MAKE Z THE FIRST DIMENSION ACTUALLY ????, probably does not change anything
|
|
33
|
+
if heightmap is not None:
|
|
34
|
+
if triangles.shape[-1] == 3:
|
|
35
|
+
b = triangles[:, :, :-1] # get rid of z before adding it again
|
|
36
|
+
else:
|
|
37
|
+
b=triangles
|
|
38
|
+
search_coords = (b[..., 0].ravel(), b[..., 1].ravel()) # 'np.where' like coords
|
|
39
|
+
heights = heightmap[search_coords]
|
|
40
|
+
|
|
41
|
+
# print('heights', heights) # en fait c'est bon car des triangles sont out -> modifie l'aire
|
|
42
|
+
|
|
43
|
+
heights = np.reshape(heights, (*b.shape[0:-1], (1)))
|
|
44
|
+
triangles = np.append(b, heights, -1) # add the height column to the coords
|
|
45
|
+
|
|
46
|
+
# compute a, b and c bond lengths for 3D triangles
|
|
47
|
+
a = ((triangles[:, 0, 0] - triangles[:, 1, 0]) ** 2 + (
|
|
48
|
+
triangles[:, 0, 1] - triangles[:, 1, 1]) ** 2 +
|
|
49
|
+
(triangles[:, 0, 2] - triangles[:, 1, 2]) ** 2) ** 0.5
|
|
50
|
+
b = ((triangles[:, 1, 0] - triangles[:, 2, 0]) ** 2 + (
|
|
51
|
+
triangles[:, 1, 1] - triangles[:, 2, 1]) ** 2 +
|
|
52
|
+
(triangles[:, 1, 2] - triangles[:, 2, 2]) ** 2) ** 0.5
|
|
53
|
+
c = ((triangles[:, 2, 0] - triangles[:, 0, 0]) ** 2 + (
|
|
54
|
+
triangles[:, 2, 1] - triangles[:, 0, 1]) ** 2 +
|
|
55
|
+
(triangles[:, 2, 2] - triangles[:, 0, 2]) ** 2) ** 0.5
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
# compute the triangle area using Heron's formula
|
|
60
|
+
# https://en.wikipedia.org/wiki/Triangle
|
|
61
|
+
s = (a + b + c) / 2.0 # semi perimeter (half of the triangle's perimeter)
|
|
62
|
+
areas = (s * (s - a) * (s - b) * (s - c)) ** 0.5
|
|
63
|
+
|
|
64
|
+
return areas.sum()
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
# def compute3D_curved_distance(point1, point2, heightmap=None, three_points_mode=False):
|
|
69
|
+
# if heightmap is None:
|
|
70
|
+
# # cannot compute 3D dist
|
|
71
|
+
# print('no valid height map --> cannot compute curved distance')
|
|
72
|
+
# return distance_between_points(point1, point2)
|
|
73
|
+
#
|
|
74
|
+
# pt1_y = int(point1[0])
|
|
75
|
+
# pt1_x = int(point1[1])
|
|
76
|
+
# # pt1_z = point1[2]
|
|
77
|
+
# pt2_y = int(point2[0])
|
|
78
|
+
# pt2_x = int(point2[1])
|
|
79
|
+
# # pt2_z = point1[2]
|
|
80
|
+
# rr, cc = draw.line(pt1_y, pt1_x,
|
|
81
|
+
# pt2_y, pt2_x)
|
|
82
|
+
# # for every point I need get the height of it and compute the real 3D distance --> not hard in fact I think
|
|
83
|
+
#
|
|
84
|
+
# dist3D = 0
|
|
85
|
+
#
|
|
86
|
+
# # print(rr, cc,'-->')
|
|
87
|
+
#
|
|
88
|
+
# if three_points_mode:
|
|
89
|
+
# # dirty hack to speed up things but ok to find the stuff then really recompute the real distance --> should be ok
|
|
90
|
+
# rr = [rr[0], rr[int(len(rr) / 2.)], rr[len(rr) - 1]]
|
|
91
|
+
# cc = [cc[0], cc[int(len(cc) / 2.)], cc[len(cc) - 1]]
|
|
92
|
+
#
|
|
93
|
+
# # print(rr,cc)
|
|
94
|
+
# # compute distance of current point with prev one --> TODO
|
|
95
|
+
# for iii in range(1, len(rr), 1):
|
|
96
|
+
# y1 = rr[iii - 1]
|
|
97
|
+
# x1 = cc[iii - 1]
|
|
98
|
+
# z1 = heightmap[y1, x1]
|
|
99
|
+
# y2 = rr[iii]
|
|
100
|
+
# x2 = cc[iii]
|
|
101
|
+
# z2 = heightmap[y2, x2]
|
|
102
|
+
# # print(y1, x1, 'height', z1)
|
|
103
|
+
# # print(y2, x2, 'height', z2)
|
|
104
|
+
#
|
|
105
|
+
# # print(y1, x1, z1, y2, x2, z2)
|
|
106
|
+
# # print('--> ', distance3D(y1, x1, z1, y2, x2, z2))
|
|
107
|
+
# # NB POINTS NEED BE SORTED --> CHECK THAT THIS IS THE CASE --> EASY MAX DIST BETWEEN CONSECUTIVE 2D POINTS CAN ONLY BE SQRT 2
|
|
108
|
+
#
|
|
109
|
+
# dist3D += distance3D(y1, x1, z1, y2, x2, z2)
|
|
110
|
+
# # print(dist3D)
|
|
111
|
+
# return dist3D
|
|
112
|
+
|
|
113
|
+
# TODO --> do that --> need sorted stuff
|
|
114
|
+
# if points are not sorted then need pavlidis sort them
|
|
115
|
+
# do pretty much the same as in the other
|
|
116
|
+
def perimeter_3D(points, heightmap,points_are_sorted=False,is_closed_contour=False):
|
|
117
|
+
if not points_are_sorted:
|
|
118
|
+
sorted_points =pavlidis(points, closed_contour=is_closed_contour)
|
|
119
|
+
else:
|
|
120
|
+
sorted_points = points
|
|
121
|
+
|
|
122
|
+
if not isinstance(sorted_points, np.ndarray):
|
|
123
|
+
sorted_points = np.asarray(sorted_points)
|
|
124
|
+
|
|
125
|
+
# NOW NEED GET HEIGHT FOR ALL POINTS --> SHOULD BE DOABLE
|
|
126
|
+
|
|
127
|
+
search_coords = (sorted_points[..., 0].ravel(), sorted_points[..., 1].ravel()) # 'np.where' like coords
|
|
128
|
+
# print('search_coords',search_coords)
|
|
129
|
+
heights = heightmap[search_coords]
|
|
130
|
+
|
|
131
|
+
|
|
132
|
+
# print(sorted_points.shape)
|
|
133
|
+
# print(heights.shape)
|
|
134
|
+
# print(heights)
|
|
135
|
+
heights=heights[..., np.newaxis]
|
|
136
|
+
# sorted_points = np.append(sorted_points, heights, -1) # add the heights dimension to the sorted points
|
|
137
|
+
sorted_points = np.append(heights,sorted_points, -1) # add the heights dimension to the sorted points
|
|
138
|
+
# sorted_points = np.hstack((heights, sorted_points)) # add the heights dimension to the sorted points
|
|
139
|
+
|
|
140
|
+
# print('sorted_points',sorted_points)
|
|
141
|
+
consecutive_distance = compute_distance_between_consecutive_points(sorted_points)
|
|
142
|
+
|
|
143
|
+
# print(consecutive_distance)
|
|
144
|
+
|
|
145
|
+
|
|
146
|
+
|
|
147
|
+
perimeter3D = np.sum(consecutive_distance)
|
|
148
|
+
|
|
149
|
+
|
|
150
|
+
# then compare to the pixel by pixel method of it and should be the same result in fact
|
|
151
|
+
# then for every point sum the distance from one point to the next...
|
|
152
|
+
|
|
153
|
+
|
|
154
|
+
|
|
155
|
+
# also find a way to order pixels and get the perimeter right
|
|
156
|
+
# si > sqrt 2 alors need a connection --> put this as a section and try connect to first or last of every list --> maybe not so hard to implement and in the end all the points should be connected but try on a real example !!!
|
|
157
|
+
# TODO
|
|
158
|
+
# do it both for 2D and 3D
|
|
159
|
+
# the ordering of the pixels is key --> really need do that
|
|
160
|
+
# then I'll have a fairly good clone of TA that would be great and fully open source!!!
|
|
161
|
+
# raise NotImplementedError
|
|
162
|
+
|
|
163
|
+
|
|
164
|
+
return perimeter3D
|
|
165
|
+
|
|
166
|
+
|
|
167
|
+
if __name__ == '__main__':
|
|
168
|
+
|
|
169
|
+
if False:
|
|
170
|
+
perimeter_3D()
|
|
171
|
+
import sys
|
|
172
|
+
sys.exit(0)
|
|
173
|
+
|
|
174
|
+
# it all seems to work but now just compute the area in a smarter way
|
|
175
|
+
|
|
176
|
+
# triangles3D= [[[2.37749672, -0.99445809,0], [1.20416474, -0.9998551,1], [2.87830002, -0.99819343,2]],[[2.37749672, -0.99445809,0], [1.20416474, -0.9998551,0], [2.87830002, -0.99819343,0]]]
|
|
177
|
+
# the second triangle is a line --> so area is 0, but 1 is the same but 3D --> in that sense it has an area
|
|
178
|
+
triangles3D = [[[2, 1, 0], [1, 1, 1], [3, 1, 2]], [[2, 1, 0], [1, 1, 0], [3, 1, 0]],
|
|
179
|
+
[[2, 1, 0], [1, 1, 0], [3, 2, 0]], [[2, 1, 0], [1, 1, 0], [2, 2, 0]],
|
|
180
|
+
[[0, 0, 0], [3, 0, 0], [3, 3, 0]]] # why 0 for the second triangle --> do I have a bug ???
|
|
181
|
+
|
|
182
|
+
triangles2D = [[[2, 1], [1, 1], [3, 1]], [[2, 1], [1, 1], [3, 1]],
|
|
183
|
+
[[2, 1], [1, 1], [3, 2]], [[2, 1], [1, 1], [2, 2]],
|
|
184
|
+
[[0, 0], [3, 0], [3, 3]]] # why 0 for the second triangle -
|
|
185
|
+
|
|
186
|
+
heightmap_flat = np.asarray([[0, 0, 0, 0, 0],
|
|
187
|
+
[0, 0, 0, 0, 0],
|
|
188
|
+
[0, 0, 0, 0, 0],
|
|
189
|
+
[0, 0, 0, 0, 0]])
|
|
190
|
+
|
|
191
|
+
# print(heightmap_flat)
|
|
192
|
+
|
|
193
|
+
heightmap_graded = np.asarray([[1, 2, 3, 4, 5],
|
|
194
|
+
[6, 7, 8, 9, 10],
|
|
195
|
+
[11, 12, 14, 15, 16],
|
|
196
|
+
[17, 18, 19, 20, 21]])
|
|
197
|
+
|
|
198
|
+
# print(heightmap_graded)
|
|
199
|
+
|
|
200
|
+
# triangles2D= [[[2.37749672, -0.99445809], [1.20416474, -0.9998551], [2.87830002, -0.99819343]],[[2.37749672, -0.99445809], [1.20416474, -0.9998551], [2.87830002, -0.99819343]]]
|
|
201
|
+
# if heightmap is provided --> get the coords from heightmap otherwise assume what is passed is already 3D
|
|
202
|
+
# check and compare 2D and 3D
|
|
203
|
+
# check also no dupes in the triangles!!!
|
|
204
|
+
print(compute_3D_surfacearea(triangles3D, heightmap=None)) # heightmap_graded # None # heightmap_flat)z
|
|
205
|
+
print(compute_3D_surfacearea(triangles2D, heightmap=None))
|
|
206
|
+
print(compute_3D_surfacearea(triangles2D, heightmap=None,stop_on_2D=True))
|
|
207
|
+
|
|
208
|
+
# if height map is provided then take it
|