driftlessmap 1.1.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (210) hide show
  1. driftlessmap/__init__.py +16 -0
  2. driftlessmap/__main__.py +5 -0
  3. driftlessmap/about.py +24 -0
  4. driftlessmap/allen_downloader.py +908 -0
  5. driftlessmap/app.py +8085 -0
  6. driftlessmap/atlas_downloader.py +370 -0
  7. driftlessmap/atlas_loader.py +526 -0
  8. driftlessmap/atlas_processor.py +784 -0
  9. driftlessmap/atlas_transform.py +111 -0
  10. driftlessmap/atlas_view.py +1435 -0
  11. driftlessmap/cell_detection.py +27 -0
  12. driftlessmap/coordinate_validation.py +19 -0
  13. driftlessmap/czi_reader.py +236 -0
  14. driftlessmap/data/WHS_atlas_labels.pkl +0 -0
  15. driftlessmap/data/allen_mice_atlas_labels.pkl +0 -0
  16. driftlessmap/data/atlas_labels.pkl +0 -0
  17. driftlessmap/data/query.csv +1328 -0
  18. driftlessmap/download_utils.py +85 -0
  19. driftlessmap/herbs.png +0 -0
  20. driftlessmap/icons/backward.svg +15 -0
  21. driftlessmap/icons/dot.svg +11 -0
  22. driftlessmap/icons/down-arrow.svg +10 -0
  23. driftlessmap/icons/fast_backward.svg +14 -0
  24. driftlessmap/icons/fast_forward.svg +14 -0
  25. driftlessmap/icons/forward.svg +14 -0
  26. driftlessmap/icons/layers/add.png +0 -0
  27. driftlessmap/icons/layers/ai.png +0 -0
  28. driftlessmap/icons/layers/eye_off.png +0 -0
  29. driftlessmap/icons/layers/eye_on.png +0 -0
  30. driftlessmap/icons/layers/eye_white.png +0 -0
  31. driftlessmap/icons/layers/hi.png +0 -0
  32. driftlessmap/icons/layers/trash.png +0 -0
  33. driftlessmap/icons/object.svg +22 -0
  34. driftlessmap/icons/sidebar/add.png +0 -0
  35. driftlessmap/icons/sidebar/atlascontrol.png +0 -0
  36. driftlessmap/icons/sidebar/atlascontrol.svg +32 -0
  37. driftlessmap/icons/sidebar/bnd.svg +14 -0
  38. driftlessmap/icons/sidebar/c_section.png +0 -0
  39. driftlessmap/icons/sidebar/c_section2.png +0 -0
  40. driftlessmap/icons/sidebar/cell.svg +24 -0
  41. driftlessmap/icons/sidebar/check.svg +9 -0
  42. driftlessmap/icons/sidebar/compare.svg +18 -0
  43. driftlessmap/icons/sidebar/contour.svg +14 -0
  44. driftlessmap/icons/sidebar/h_section.png +0 -0
  45. driftlessmap/icons/sidebar/info.svg +14 -0
  46. driftlessmap/icons/sidebar/layers.png +0 -0
  47. driftlessmap/icons/sidebar/layers.svg +23 -0
  48. driftlessmap/icons/sidebar/line.svg +10 -0
  49. driftlessmap/icons/sidebar/link.svg +18 -0
  50. driftlessmap/icons/sidebar/link_off.svg +18 -0
  51. driftlessmap/icons/sidebar/merge.svg +11 -0
  52. driftlessmap/icons/sidebar/object.svg +13 -0
  53. driftlessmap/icons/sidebar/probe.png +0 -0
  54. driftlessmap/icons/sidebar/probe.svg +23 -0
  55. driftlessmap/icons/sidebar/rotation_horizontal.svg +14 -0
  56. driftlessmap/icons/sidebar/rotation_vertical.svg +14 -0
  57. driftlessmap/icons/sidebar/s_section.png +0 -0
  58. driftlessmap/icons/sidebar/tool.png +0 -0
  59. driftlessmap/icons/sidebar/tool.svg +19 -0
  60. driftlessmap/icons/sidebar/trash.png +0 -0
  61. driftlessmap/icons/sidebar/tree_checked.svg +10 -0
  62. driftlessmap/icons/sidebar/treeview.png +0 -0
  63. driftlessmap/icons/sidebar/treeview.svg +10 -0
  64. driftlessmap/icons/sidebar/treeview2.png +0 -0
  65. driftlessmap/icons/sidebar/virus.svg +24 -0
  66. driftlessmap/icons/tdown.svg +16 -0
  67. driftlessmap/icons/toolbar/accept.svg +18 -0
  68. driftlessmap/icons/toolbar/accept2.svg +24 -0
  69. driftlessmap/icons/toolbar/aim.svg +44 -0
  70. driftlessmap/icons/toolbar/aim_not.svg +28 -0
  71. driftlessmap/icons/toolbar/anchor.svg +14 -0
  72. driftlessmap/icons/toolbar/anticlockwise_rotation.svg +12 -0
  73. driftlessmap/icons/toolbar/atlas_icon.png +0 -0
  74. driftlessmap/icons/toolbar/boundary_register.svg +18 -0
  75. driftlessmap/icons/toolbar/cancel.svg +32 -0
  76. driftlessmap/icons/toolbar/cell_select.svg +22 -0
  77. driftlessmap/icons/toolbar/cell_select_not.svg +12 -0
  78. driftlessmap/icons/toolbar/check.svg +9 -0
  79. driftlessmap/icons/toolbar/clockwise_rotation.svg +11 -0
  80. driftlessmap/icons/toolbar/closed_path.svg +16 -0
  81. driftlessmap/icons/toolbar/closed_path2 copy.svg +19 -0
  82. driftlessmap/icons/toolbar/closed_path2.svg +20 -0
  83. driftlessmap/icons/toolbar/eraser.png +0 -0
  84. driftlessmap/icons/toolbar/eraser.svg +19 -0
  85. driftlessmap/icons/toolbar/eye.svg +17 -0
  86. driftlessmap/icons/toolbar/eye_closed.svg +19 -0
  87. driftlessmap/icons/toolbar/fill.svg +12 -0
  88. driftlessmap/icons/toolbar/gps.svg +15 -0
  89. driftlessmap/icons/toolbar/h_flip.png +0 -0
  90. driftlessmap/icons/toolbar/handle.png +0 -0
  91. driftlessmap/icons/toolbar/image_icon.png +0 -0
  92. driftlessmap/icons/toolbar/image_icon.svg +25 -0
  93. driftlessmap/icons/toolbar/info.svg +14 -0
  94. driftlessmap/icons/toolbar/inpart.png +0 -0
  95. driftlessmap/icons/toolbar/inpart.svg +17 -0
  96. driftlessmap/icons/toolbar/lasso.png +0 -0
  97. driftlessmap/icons/toolbar/lasso.svg +14 -0
  98. driftlessmap/icons/toolbar/left90.png +0 -0
  99. driftlessmap/icons/toolbar/line.svg +10 -0
  100. driftlessmap/icons/toolbar/line_sites.svg +11 -0
  101. driftlessmap/icons/toolbar/linear_silicon.png +0 -0
  102. driftlessmap/icons/toolbar/linear_silicon.svg +88 -0
  103. driftlessmap/icons/toolbar/list.svg +14 -0
  104. driftlessmap/icons/toolbar/location.svg +14 -0
  105. driftlessmap/icons/toolbar/magic-wand.svg +16 -0
  106. driftlessmap/icons/toolbar/magic_white.png +0 -0
  107. driftlessmap/icons/toolbar/mask.svg +10 -0
  108. driftlessmap/icons/toolbar/match.svg +20 -0
  109. driftlessmap/icons/toolbar/matchbnd.svg +18 -0
  110. driftlessmap/icons/toolbar/matching.svg +36 -0
  111. driftlessmap/icons/toolbar/merge.svg +11 -0
  112. driftlessmap/icons/toolbar/move_down.png +0 -0
  113. driftlessmap/icons/toolbar/move_left.png +0 -0
  114. driftlessmap/icons/toolbar/move_right.png +0 -0
  115. driftlessmap/icons/toolbar/move_up.png +0 -0
  116. driftlessmap/icons/toolbar/moving.png +0 -0
  117. driftlessmap/icons/toolbar/multi-probe.svg +119 -0
  118. driftlessmap/icons/toolbar/multi_pencil.svg +23 -0
  119. driftlessmap/icons/toolbar/multi_probe.png +0 -0
  120. driftlessmap/icons/toolbar/object.svg +13 -0
  121. driftlessmap/icons/toolbar/open_path.svg +22 -0
  122. driftlessmap/icons/toolbar/outpart.png +0 -0
  123. driftlessmap/icons/toolbar/outpart.svg +26 -0
  124. driftlessmap/icons/toolbar/pencil.png +0 -0
  125. driftlessmap/icons/toolbar/pencil.svg +19 -0
  126. driftlessmap/icons/toolbar/plasso.png +0 -0
  127. driftlessmap/icons/toolbar/probe.svg +19 -0
  128. driftlessmap/icons/toolbar/radar.svg +32 -0
  129. driftlessmap/icons/toolbar/rotation.svg +45 -0
  130. driftlessmap/icons/toolbar/rotation_clockwise.svg +18 -0
  131. driftlessmap/icons/toolbar/rotation_counter_clockwise.svg +18 -0
  132. driftlessmap/icons/toolbar/ruler.svg +27 -0
  133. driftlessmap/icons/toolbar/separate_sites.svg +13 -0
  134. driftlessmap/icons/toolbar/single_pencil.svg +16 -0
  135. driftlessmap/icons/toolbar/toa.svg +11 -0
  136. driftlessmap/icons/toolbar/toa_delete.svg +36 -0
  137. driftlessmap/icons/toolbar/toaa.svg +11 -0
  138. driftlessmap/icons/toolbar/toh.svg +11 -0
  139. driftlessmap/icons/toolbar/toh_delete.svg +36 -0
  140. driftlessmap/icons/toolbar/tohh.svg +11 -0
  141. driftlessmap/icons/toolbar/trans.png +0 -0
  142. driftlessmap/icons/toolbar/trans.svg +16 -0
  143. driftlessmap/icons/toolbar/triangulation.svg +10 -0
  144. driftlessmap/icons/toolbar/two_window.png +0 -0
  145. driftlessmap/icons/toolbar/unmerge.svg +16 -0
  146. driftlessmap/icons/toolbar/v_flip.png +0 -0
  147. driftlessmap/icons/toolbar/virus.svg +24 -0
  148. driftlessmap/icons/toolbar/virus_register.svg +31 -0
  149. driftlessmap/icons/toolbar/vis2d.svg +29 -0
  150. driftlessmap/icons/toolbar/window2.png +0 -0
  151. driftlessmap/icons/toolbar/window3.png +0 -0
  152. driftlessmap/icons/toolbar/window4.png +0 -0
  153. driftlessmap/icons/tree_close.svg +14 -0
  154. driftlessmap/icons/tree_open.svg +14 -0
  155. driftlessmap/icons/up-arrow.svg +10 -0
  156. driftlessmap/image_curves.py +579 -0
  157. driftlessmap/image_reader.py +186 -0
  158. driftlessmap/image_stacks.py +359 -0
  159. driftlessmap/image_view.py +646 -0
  160. driftlessmap/images_reader.py +5 -0
  161. driftlessmap/label_tree.py +278 -0
  162. driftlessmap/layer_validation.py +25 -0
  163. driftlessmap/layers_control.py +554 -0
  164. driftlessmap/main_window.ui +883 -0
  165. driftlessmap/movable_points.py +254 -0
  166. driftlessmap/obj_items.py +122 -0
  167. driftlessmap/object_control.py +1762 -0
  168. driftlessmap/persistence.py +376 -0
  169. driftlessmap/popup_message.py +16 -0
  170. driftlessmap/probe_csv.py +319 -0
  171. driftlessmap/probe_reconstruction.py +409 -0
  172. driftlessmap/probe_utiles.py +1442 -0
  173. driftlessmap/qss/atlas_view_group_box.qss +15 -0
  174. driftlessmap/qss/box_label.qss +7 -0
  175. driftlessmap/qss/channel_selector.qss +19 -0
  176. driftlessmap/qss/color_combo.qss +121 -0
  177. driftlessmap/qss/decor_label.qss +9 -0
  178. driftlessmap/qss/dialogs.qss +11 -0
  179. driftlessmap/qss/hidden_line_edit.qss +5 -0
  180. driftlessmap/qss/label_tree.qss +123 -0
  181. driftlessmap/qss/main_window.qss +243 -0
  182. driftlessmap/qss/menu_bar.qss +42 -0
  183. driftlessmap/qss/multi_handle_slider.qss +14 -0
  184. driftlessmap/qss/obj_ctrl_bottom_button.qss +29 -0
  185. driftlessmap/qss/object_text_button.qss +19 -0
  186. driftlessmap/qss/page_control.qss +36 -0
  187. driftlessmap/qss/rotation_button.qss +9 -0
  188. driftlessmap/qss/side_bar.qss +23 -0
  189. driftlessmap/qss/spinbox.qss +106 -0
  190. driftlessmap/qss/tabs.qss +211 -0
  191. driftlessmap/qss/tool_bar.qss +77 -0
  192. driftlessmap/resources.py +34 -0
  193. driftlessmap/roi_analysis.py +375 -0
  194. driftlessmap/run_driftlessmap.py +4 -0
  195. driftlessmap/slice_stacks.py +268 -0
  196. driftlessmap/slice_validation.py +20 -0
  197. driftlessmap/toolbox.py +569 -0
  198. driftlessmap/triangulation.py +517 -0
  199. driftlessmap/triangulation_points.py +108 -0
  200. driftlessmap/user_settings.py +92 -0
  201. driftlessmap/uuuuuu.py +1168 -0
  202. driftlessmap/version.py +3 -0
  203. driftlessmap/widgets_utils.py +140 -0
  204. driftlessmap/wtiles.py +715 -0
  205. driftlessmap-1.1.0.dist-info/METADATA +186 -0
  206. driftlessmap-1.1.0.dist-info/RECORD +210 -0
  207. driftlessmap-1.1.0.dist-info/WHEEL +5 -0
  208. driftlessmap-1.1.0.dist-info/entry_points.txt +2 -0
  209. driftlessmap-1.1.0.dist-info/licenses/LICENSE.txt +23 -0
  210. driftlessmap-1.1.0.dist-info/top_level.txt +1 -0
driftlessmap/uuuuuu.py ADDED
@@ -0,0 +1,1168 @@
1
+ import os
2
+ import numpy as np
3
+ import math
4
+ import pandas as pd
5
+ import cv2
6
+ import pickle
7
+ import colorsys
8
+ import pyqtgraph as pg
9
+ import pyqtgraph.opengl as gl
10
+ import scipy.ndimage as ndi
11
+ from scipy.interpolate import interp1d, splprep, splev
12
+ from .coordinate_validation import coordinates_in_bounds
13
+ from .persistence import load_driftlessmap_file
14
+ from .resources import resource_path, resolve_qss_resource_urls
15
+
16
+
17
+ def read_qss_file(qss_file_name):
18
+ with open(resource_path(qss_file_name), "r", encoding="UTF-8") as file:
19
+ return resolve_qss_resource_urls(file.read())
20
+
21
+
22
+ def check_loading_pickle_file(file_path, expected_kind=None):
23
+ return load_driftlessmap_file(file_path, expected_kind=expected_kind)
24
+
25
+
26
+ def read_excel_file(file_path):
27
+ msg = None
28
+ file_name, file_extension = os.path.splitext(file_path)
29
+ if file_extension == ".csv":
30
+ df = pd.read_csv(file_path)
31
+ elif file_extension == ".xlsx":
32
+ df = pd.read_excel(file_path)
33
+ else:
34
+ df = None
35
+ msg = "Only CSV file and Excel file works."
36
+ return df, msg
37
+
38
+
39
+ def read_label(file):
40
+ lines = []
41
+ for line in file:
42
+ lines.append(line)
43
+
44
+ n_lines = len(lines)
45
+ label_index = np.zeros(n_lines - 14, "i")
46
+ label_index[:] = np.nan
47
+ label_colors = np.zeros((n_lines - 14, 3), "i")
48
+ label_colors[:] = np.nan
49
+ label_names = []
50
+ for i in range(n_lines - 14):
51
+ split_lines = lines[i + 14].split()
52
+ label_index[i] = int(split_lines[0])
53
+ label_colors[i] = np.array(
54
+ [split_lines[1], split_lines[2], split_lines[3]]
55
+ ).astype(int)
56
+ split_lines2 = lines[i + 14].split('"')
57
+ label_names.append(split_lines2[1])
58
+
59
+ return label_index, label_names, label_colors
60
+
61
+
62
+ def rotation_x(theta):
63
+ ct = np.cos(theta)
64
+ st = np.sin(theta)
65
+ rx = np.array([[1, 0, 0], [0, ct, -st], [0, st, ct]])
66
+ return rx
67
+
68
+
69
+ def rotation_y(theta):
70
+ ct = np.cos(theta)
71
+ st = np.sin(theta)
72
+ ry = np.array([[ct, 0, st], [0, 1, 0], [-st, 0, ct]])
73
+ return ry
74
+
75
+
76
+ def rotation_z(theta):
77
+ ct = np.cos(theta)
78
+ st = np.sin(theta)
79
+ rz = np.array([[ct, -st, 0], [st, ct, 0], [0, 0, 1]])
80
+ return rz
81
+
82
+
83
+ def d2td3(pos2d, ax, ay, o):
84
+ pos3d = pos2d[0] * ax + pos2d[1] * ay + o
85
+ return pos3d
86
+
87
+
88
+ def get_region_label(data, label_data, bregma):
89
+ region_label = []
90
+ for i in range(len(data)):
91
+ temp = data[i] + bregma
92
+ temp = temp.astype(int)
93
+ region_label.append(label_data[temp[0], temp[1], temp[2]])
94
+ return region_label
95
+
96
+
97
+ def get_region_label_info(region_label, label_info):
98
+ unique_label = np.sort(np.unique(region_label))
99
+ label_names = []
100
+ label_acronym = []
101
+ label_color = []
102
+ region_count = []
103
+ for i in range(len(unique_label)):
104
+ # print(unique_label[i])
105
+ if unique_label[i] == 0:
106
+ label_names.append(" ")
107
+ label_acronym.append(" ")
108
+ label_color.append((128, 128, 128))
109
+ else:
110
+ da_ind = np.where(label_info["index"] == unique_label[i])[0][0]
111
+ label_names.append(label_info["label"][da_ind])
112
+ label_acronym.append(label_info["abbrev"][da_ind])
113
+ label_color.append(label_info["color"][da_ind])
114
+
115
+ region_count.append(len(np.where(np.ravel(region_label) == unique_label[i])[0]))
116
+
117
+ return region_count, label_names, label_acronym, label_color, unique_label
118
+
119
+
120
+ def calculate_virus_info(data_list, pieces_names, label_data, label_info, bregma):
121
+ temp_data = data_list[0]
122
+ for i in range(1, len(data_list)):
123
+ temp_data = np.vstack([temp_data, data_list[i]])
124
+
125
+ data = temp_data.astype(int)
126
+
127
+ # data = np.array([vox_data[0]])
128
+ # for i in range(1, len(vox_data)):
129
+ # if np.any(vox_data[i] != data[-1]):
130
+ # data = np.vstack([data, vox_data[i]])
131
+
132
+ region_label = get_region_label(data, label_data, bregma)
133
+ unique_region = np.sort(np.unique(region_label))
134
+ region_volume = []
135
+ for c_region in unique_region:
136
+ region_volume.append(len(np.where(label_data == c_region)[0]))
137
+
138
+ # print(region_volume)
139
+ (
140
+ region_count,
141
+ label_names,
142
+ label_acronym,
143
+ label_color,
144
+ unique_label,
145
+ ) = get_region_label_info(region_label, label_info)
146
+ # print(region_count)
147
+
148
+ res_dict = {
149
+ "object_name": "virus",
150
+ "data": data_list,
151
+ "pieces_names": pieces_names,
152
+ "label_id": unique_label,
153
+ "label_name": label_names,
154
+ "label_acronym": label_acronym,
155
+ "label_color": label_color,
156
+ "region_volume": region_volume,
157
+ "virus_volume": region_count,
158
+ }
159
+
160
+ return res_dict
161
+
162
+
163
+ def calculate_cells_info(data_list, pieces_names, label_data, label_info, bregma):
164
+ data = data_list[0]
165
+ for i in range(1, len(data_list)):
166
+ data = np.vstack([data, data_list[i]])
167
+
168
+ region_label = get_region_label(data, label_data, bregma)
169
+ (
170
+ region_count,
171
+ label_names,
172
+ label_acronym,
173
+ label_color,
174
+ unique_label,
175
+ ) = get_region_label_info(region_label, label_info)
176
+
177
+ res_dict = {
178
+ "object_name": "cell",
179
+ "pieces_names": pieces_names,
180
+ "data": data_list,
181
+ "label_name": label_names,
182
+ "label_acronym": label_acronym,
183
+ "label_color": label_color,
184
+ "region_count": region_count,
185
+ }
186
+ return res_dict
187
+
188
+
189
+ def calculate_drawing_info(data_list, pieces_names, label_data, label_info, bregma):
190
+ data = data_list[0]
191
+ for i in range(1, len(data_list)):
192
+ data = np.vstack([data, data_list[i]])
193
+ # print(data)
194
+ if "area" in pieces_names[0]:
195
+ plot_mode = "area"
196
+ else:
197
+ plot_mode = "line"
198
+
199
+ region_label = get_region_label(data, label_data, bregma)
200
+ (
201
+ region_count,
202
+ label_names,
203
+ label_acronym,
204
+ label_color,
205
+ unique_label,
206
+ ) = get_region_label_info(region_label, label_info)
207
+
208
+ res_dict = {
209
+ "object_name": "drawing",
210
+ "pieces_names": pieces_names,
211
+ "data": data_list,
212
+ "label_id": unique_label,
213
+ "label_name": label_names,
214
+ "label_acronym": label_acronym,
215
+ "label_color": label_color,
216
+ "region_count": region_count,
217
+ "plot_mode": plot_mode,
218
+ }
219
+ return res_dict
220
+
221
+
222
+ def order_contour_pnt(pnt):
223
+ order_ind = []
224
+ x_min = np.min(pnt[:, 0])
225
+ left_ind = np.where(pnt[:, 0] == x_min)[0]
226
+ if len(left_ind) > 1:
227
+ low_ind = np.where(pnt[left_ind, :] == np.min(pnt[left_ind, :]))[0]
228
+ left_ind = left_ind[low_ind]
229
+ left_pnt = pnt[left_ind, :]
230
+ lower_inds = np.where(pnt[:, 1] <= left_pnt[1])[0]
231
+ lower_pnts = pnt[:, lower_inds]
232
+
233
+
234
+ def calculate_contour_line(data):
235
+ data = np.asarray(data)
236
+ res = splprep([data[:, 0], data[:, 1], data[:, 2]], s=2)
237
+ tck = res[0]
238
+ # x_knots, y_knots, z_knots = splev(tck[0], tck)
239
+ u_fine = np.linspace(0, 1, len(data))
240
+ x_fine, y_fine, z_fine = splev(u_fine, tck)
241
+ pnts = np.stack([x_fine, y_fine, z_fine], axis=1)
242
+ # print(pnts)
243
+ return pnts
244
+
245
+
246
+ def hex2rgb(hex):
247
+ if "#" in hex:
248
+ hex = hex.lstrip("#")
249
+ rgb_color = [int(hex[i : i + 2], 16) for i in (0, 2, 4)]
250
+ else:
251
+ if len(hex) == 6:
252
+ rgb_color = [int(hex[i : i + 2], 16) for i in (0, 2, 4)]
253
+ return rgb_color[0], rgb_color[1], rgb_color[2]
254
+
255
+
256
+ # @jit()
257
+ def hsv2rgb(h, s, v):
258
+ # h [0, 1], s, v [0, 1]
259
+ h = h * 360
260
+ c = v * s
261
+ m = v - c
262
+ x = c * (1 - np.abs(np.mod(h / 60, 2) - 1))
263
+ if 0 <= h < 60:
264
+ r, g, b = (c + m, x + m, m)
265
+ elif 60 <= h < 120:
266
+ r, g, b = (x + m, c + m, m)
267
+ elif 120 <= h < 180:
268
+ r, g, b = (m, c + m, x + m)
269
+ elif 180 <= h < 240:
270
+ r, g, b = (m, x + m, c + m)
271
+ elif 240 <= h < 300:
272
+ r, g, b = (x + m, m, c + m)
273
+ elif 300 <= h < 360:
274
+ r, g, b = (c + m, m, x + m)
275
+ else:
276
+ r, g, b = (m, m, m)
277
+ r = r * 65535
278
+ b = b * 65535
279
+ g = g * 65535
280
+ return r, g, b
281
+
282
+
283
+ def color_img(h, s, v):
284
+ r, g, b = hsv2rgb(h, s, v)
285
+ da_image = cv2.merge((r, g, b))
286
+ return da_image
287
+
288
+
289
+ def merge_channels_into_single_img(czi_img, channel_colors):
290
+ merged_img = np.zeros((czi_img.shape[0], czi_img.shape[1], 3))
291
+ frac = 1 / len(channel_colors)
292
+ # print(frac)
293
+ for i in range(len(channel_colors)):
294
+ temp_v = czi_img[:, :, i] / 65535
295
+ temp_h = channel_colors[i][0]
296
+ temp_s = channel_colors[i][1]
297
+ # print(temp_h, temp_s)
298
+ da_img = color_img(temp_h, temp_s, temp_v)
299
+ merged_img = merged_img + frac * da_img
300
+ return merged_img
301
+
302
+
303
+ def make_color_lut(channel_color: tuple, bit_level: int):
304
+ r, g, b = colorsys.hsv_to_rgb(channel_color[0], channel_color[1], channel_color[2])
305
+ colors = [(0, 0, 0), (r * 255, g * 255, b * 255)]
306
+ color_map = pg.ColorMap(pos=[0, 1], color=colors)
307
+ da_lut = color_map.getLookupTable(nPts=bit_level, mode=pg.ColorMap.FLOAT)
308
+ da_lut = da_lut * 255
309
+ return da_lut
310
+
311
+
312
+ def get_qhsv_from_czi_hsv(hsv_color: tuple):
313
+ """
314
+ Get QColor HSV color format (360, 255, 255) from czi HSV color format (1, 1, 1).
315
+ :param hsv_color: (float [0., 1.], float [0., 1.], float [0., 1.])
316
+ :return: QColor
317
+ """
318
+ h_val = int(hsv_color[0] * 360)
319
+ s_val = int(hsv_color[1] * 255)
320
+ v_val = int(hsv_color[2] * 255)
321
+ da_color = (h_val, s_val, v_val)
322
+ return da_color
323
+
324
+
325
+ def gamma_line(input, lims, gamma, depth_level):
326
+ inv_gamma = 1.0 / gamma
327
+ y = np.zeros(len(input))
328
+ inds = np.logical_and(input >= lims[0], input <= lims[1])
329
+ y[inds] = (
330
+ np.power((input[inds] - lims[0]) / (lims[1] - lims[0]), gamma) * depth_level
331
+ )
332
+ y[input <= lims[0]] = 0
333
+ y[input >= lims[1]] = depth_level
334
+ return y
335
+
336
+
337
+ def crop_landscape(image, dim):
338
+ r = (dim[0] / image.shape[0]) / (dim[0] / dim[1])
339
+ nw = int(image.shape[1] * r)
340
+
341
+ resized = cv2.resize(image, (nw, int(dim[1])), interpolation=cv2.INTER_AREA)
342
+
343
+ half_width = int(dim[0]) / 2
344
+ half_shape_width = int(resized.shape[1]) / 2
345
+
346
+ start_x = half_shape_width - half_width
347
+ end_x = half_width + half_shape_width
348
+ cropped = resized[0 : dim[1], start_x:end_x]
349
+
350
+ return cropped
351
+
352
+
353
+ def crop_portrait(image, dim):
354
+ r = dim[1] / image.shape[1] / (dim[1] / dim[0])
355
+ nh = int(image.shape[0] * r)
356
+
357
+ resized = cv2.resize(image, (int(dim[0]), nh), interpolation=cv2.INTER_AREA)
358
+ half_height = int(dim[1]) / 2
359
+ half_shape_height = int(resized.shape[0]) / 2
360
+
361
+ start_y = half_shape_height - half_height
362
+ end_y = half_height + half_shape_height
363
+ cropped = resized[start_y:end_y, 0 : dim[0]]
364
+
365
+ return cropped
366
+
367
+
368
+ def create_other_size(image, file_name, dim, location):
369
+ # 1 => width index, 0 => height index
370
+ if image.shape[0] > image.shape[1]:
371
+ cropped = crop_portrait(image, dim)
372
+ else:
373
+ cropped = crop_landscape(image, dim)
374
+
375
+ cv2.imwrite(os.path.join(location, file_name), cropped)
376
+
377
+
378
+ def make_hist_data(image_data, max_val):
379
+ hist_data_list = []
380
+ for i in range(image_data.shape[2]):
381
+ if np.max(image_data[:, :, i]) == 0:
382
+ da_bins = max_val
383
+ else:
384
+ da_bins = np.max(image_data[:, :, i])
385
+ hist_y, x = np.histogram(image_data[:, :, i], bins=da_bins)
386
+ y = np.log1p(hist_y)
387
+ y = y / np.max(y) * max_val
388
+ y = np.append(y, 0)
389
+ sfunc = interp1d(x, y, "cubic")
390
+ inter_x = np.linspace(np.min(x), np.max(x), 200)
391
+ inter_y = sfunc(inter_x)
392
+ inter_y[inter_y < 0] = 0
393
+ hist_data_list.append([inter_x, inter_y])
394
+ return hist_data_list
395
+
396
+
397
+ def rect_contains(rect, point):
398
+ if point[0] < rect[0]:
399
+ return False
400
+ elif point[1] < rect[1]:
401
+ return False
402
+ elif point[0] > rect[2] + rect[0]:
403
+ return False
404
+ elif point[1] > rect[3] + rect[1]:
405
+ return False
406
+ return True
407
+
408
+
409
+ def get_warp_matrix(src_tri_pnts, dst_tri_pnts):
410
+ # Given a pair of triangles, find the affine transform.
411
+ warp_mat = cv2.getAffineTransform(
412
+ np.float32(src_tri_pnts), np.float32(dst_tri_pnts)
413
+ )
414
+ return warp_mat
415
+
416
+
417
+ def apply_affine_transform(src_img, warp_mat, size_dst):
418
+ # Apply the Affine Transform just found to the src image
419
+ dst = cv2.warpAffine(
420
+ src_img.astype(np.float32),
421
+ warp_mat,
422
+ (size_dst[0], size_dst[1]),
423
+ None,
424
+ flags=cv2.INTER_LINEAR,
425
+ borderMode=cv2.BORDER_REFLECT_101,
426
+ )
427
+ return dst
428
+
429
+
430
+ def warp_triangle(img1, img2, t1, t2, is_rgb=False):
431
+ # Find bounding rectangle for each triangle
432
+ r1 = cv2.boundingRect(t1.astype(np.float32))
433
+ r2 = cv2.boundingRect(t2.astype(np.float32))
434
+
435
+ # Offset points by left top corner of the respective rectangles
436
+ t1_rect = t1 - r1[:2]
437
+ t2_rect = t2 - r2[:2]
438
+ t2_rect_int = t2_rect.astype(int)
439
+
440
+ # Get mask by filling triangle
441
+ if is_rgb:
442
+ mask = np.zeros((r2[3], r2[2], img1.shape[2]), dtype=np.float32)
443
+ cv2.fillConvexPoly(
444
+ mask, np.int32(t2_rect_int), tuple(np.repeat(1.0, img1.shape[2])), 16, 0
445
+ )
446
+ else:
447
+ mask = np.zeros((r2[3], r2[2]), dtype=np.float32)
448
+ cv2.fillConvexPoly(mask, np.int32(t2_rect_int), 1, 16, 0)
449
+
450
+ # Apply warpImage to small rectangular patches
451
+ img1_rect = img1[r1[1] : r1[1] + r1[3], r1[0] : r1[0] + r1[2]]
452
+ # img2Rect = np.zeros((r2[3], r2[2]), dtype = img1Rect.dtype)
453
+
454
+ size = (r2[2], r2[3])
455
+
456
+ warp_mat = get_warp_matrix(t1_rect, t2_rect)
457
+ img2_rect = apply_affine_transform(img1_rect, warp_mat, size)
458
+ img2_rect = img2_rect * mask
459
+
460
+ # Copy triangular region of the rectangular patch to the output image
461
+ yr = (r2[0], r2[0] + r2[2])
462
+ xr = (r2[1], r2[1] + r2[3])
463
+ if is_rgb:
464
+ img2[xr[0] : xr[1], yr[0] : yr[1]] = img2[xr[0] : xr[1], yr[0] : yr[1]] * (
465
+ tuple(np.repeat(1.0, img1.shape[2])) - mask
466
+ )
467
+ else:
468
+ img2[xr[0] : xr[1], yr[0] : yr[1]] = img2[xr[0] : xr[1], yr[0] : yr[1]] * (
469
+ 1 - mask
470
+ )
471
+ img2[xr[0] : xr[1], yr[0] : yr[1]] = img2[xr[0] : xr[1], yr[0] : yr[1]] + img2_rect
472
+
473
+
474
+ def warp_points(pnts, t1, t2):
475
+ # Find bounding rectangle for each triangle
476
+ # r1 = cv2.boundingRect(t1.astype(np.float32))
477
+ # r2 = cv2.boundingRect(t2.astype(np.float32))
478
+ # print(r1)
479
+ # print(r2)
480
+
481
+ # pnts =
482
+
483
+ da_pnts = np.hstack([pnts, np.ones((len(pnts), 1))])
484
+ # Offset points by left top corner of the respective rectangles
485
+ # t1_rect = t1 - r1[:2]
486
+ # t2_rect = t2 - r2[:2]
487
+
488
+ warp_mat = get_warp_matrix(t1, t2)
489
+ output = np.dot(warp_mat, da_pnts.T).T
490
+
491
+ return output
492
+
493
+
494
+ # calculate delanauy triangle
495
+ def calculateDelaunayTriangles(rect, points):
496
+ # create subdiv
497
+ subdiv = cv2.Subdiv2D(rect)
498
+
499
+ # Insert points into subdiv
500
+ for p in points:
501
+ subdiv.insert(p)
502
+
503
+ triangleList = subdiv.getTriangleList()
504
+
505
+ delaunayTri = []
506
+
507
+ pt = []
508
+
509
+ for t in triangleList:
510
+ pt.append((t[0], t[1]))
511
+ pt.append((t[2], t[3]))
512
+ pt.append((t[4], t[5]))
513
+
514
+ pt1 = (t[0], t[1])
515
+ pt2 = (t[2], t[3])
516
+ pt3 = (t[4], t[5])
517
+
518
+ if (
519
+ rect_contains(rect, pt1)
520
+ and rect_contains(rect, pt2)
521
+ and rect_contains(rect, pt3)
522
+ ):
523
+ ind = []
524
+ for j in range(0, 3):
525
+ for k in range(0, len(points)):
526
+ if (
527
+ abs(pt[j][0] - points[k][0]) < 1.0
528
+ and abs(pt[j][1] - points[k][1]) < 1.0
529
+ ):
530
+ ind.append(k)
531
+ if len(ind) == 3:
532
+ delaunayTri.append((ind[0], ind[1], ind[2]))
533
+
534
+ pt = []
535
+
536
+ return delaunayTri
537
+
538
+
539
+ def get_vertex_ind_in_triangle(subdiv):
540
+ triangles = subdiv.getTriangleList()
541
+ n_triangles = len(triangles)
542
+ tri_vet_inds = []
543
+ for i in range(n_triangles):
544
+ da_triangle = triangles[i]
545
+ p1 = [da_triangle[0], da_triangle[1]]
546
+ p2 = [da_triangle[2], da_triangle[3]]
547
+ p3 = [da_triangle[4], da_triangle[5]]
548
+ tri_vet_inds.append(
549
+ [subdiv.locate(p1)[2], subdiv.locate(p2)[2], subdiv.locate(p3)[2]]
550
+ )
551
+ tri_vet_inds = np.asarray(tri_vet_inds) - 4
552
+ return tri_vet_inds
553
+
554
+
555
+ def get_pnts_triangle_ind(tri_vet_inds, tri_data, size, pnts):
556
+ # import cv2
557
+ # import numpy as np
558
+ # img_rec = (0, 0, 100, 200)
559
+ # da_triangle = np.array([[0, 0], [0, 50], [100, 100]])
560
+ # size = (200, 100)
561
+ # pnts = np.array([[0, 1], [0, 2], [60, 200]])
562
+
563
+ update_pnts = pnts.copy()
564
+ n_pnts = len(pnts)
565
+ loc = np.zeros(n_pnts)
566
+ loc[:] = np.nan
567
+ da_order = []
568
+
569
+ ct_list = []
570
+ for i in range(len(tri_vet_inds)):
571
+ da_inds = tri_vet_inds[i]
572
+ da_triangle = np.array(
573
+ [tri_data[da_inds[0]], tri_data[da_inds[1]], tri_data[da_inds[2]]]
574
+ )
575
+ mask = np.zeros(size, dtype=np.uint8)
576
+ cv2.fillPoly(mask, pts=[da_triangle], color=255)
577
+ ct, hc = cv2.findContours(
578
+ image=mask, mode=cv2.RETR_TREE, method=cv2.CHAIN_APPROX_NONE
579
+ )
580
+ ct_list.append(ct[0])
581
+
582
+ # range_y = (np.min(da_triangle[:, 1]), np.max(da_triangle[:, 1]))
583
+ # range_x = (np.min(da_triangle[:, 0]), np.max(da_triangle[:, 0]))
584
+ #
585
+ # valid_pnts_ind = [ind for ind in range(n_pnts) if range_x[0] <= pnts[ind][0] <= range_x[1] and range_y[0] <= pnts[ind][1] <= range_y[1]]
586
+ # valid_pnts_ind = [ind for ind in valid_pnts_ind if ind not in da_order]
587
+ # valid_pnts = pnts[valid_pnts_ind]
588
+ # for j in range(len(valid_pnts)):
589
+ # res = cv2.pointPolygonTest(ct_list[i], (int(pnts[j][0]), int(pnts[j][1])), True)
590
+ # if res >= 0:
591
+ # loc.append(i)
592
+ # da_order.append(valid_pnts_ind[j])
593
+
594
+ # temp = np.zeros(len(update_pnts))
595
+ #
596
+ #
597
+ # for i in range(len(tri_vet_inds)):
598
+ # da_
599
+ #
600
+ for i in range(len(pnts)):
601
+ for j in range(len(ct_list)):
602
+ da_ct = ct_list[j]
603
+ res = cv2.pointPolygonTest(da_ct, (int(pnts[i][0]), int(pnts[i][1])), False)
604
+ if res >= 0:
605
+ loc[i] = j
606
+ break
607
+
608
+ return loc
609
+
610
+
611
+ def get_sides_points(img_size):
612
+ size0 = img_size[1] - 1
613
+ size1 = img_size[0] - 1
614
+ side_lines = np.asarray(
615
+ [
616
+ [[0, 0], [size0, 0]],
617
+ [[size0, 0], [size0, size1]],
618
+ [[0, size1], [size0, size1]],
619
+ [[0, 0], [0, size1]],
620
+ ]
621
+ )
622
+ corner_points = [[0, 0], [size0, 0], [size0, size1], [0, size1]]
623
+ return side_lines, corner_points
624
+
625
+
626
+ def num_side_pnt_changed(num_pnt, corner_points, side_lines):
627
+ n_pnts_to_make = num_pnt - 2
628
+ onside_data = corner_points.copy()
629
+ if n_pnts_to_make > 0:
630
+ for i in range(4):
631
+ da_line = side_lines[i]
632
+ for j in range(n_pnts_to_make):
633
+ inline_point = da_line[0] + (da_line[1] - da_line[0]) / (
634
+ n_pnts_to_make + 1
635
+ ) * (j + 1)
636
+ onside_data.append([int(inline_point[0]), int(inline_point[1])])
637
+ return onside_data
638
+
639
+
640
+ def match_sides_points(rect_atlas, size_atlas, rect_image, size_image):
641
+ x_factor = rect_atlas[2] / rect_image[2]
642
+ y_factor = rect_atlas[3] / rect_image[3]
643
+
644
+ actual_right_dist_image = size_image[1] - (rect_image[0] + rect_image[2])
645
+ actual_bottom_dist_image = size_image[0] - (rect_image[1] + rect_image[3])
646
+
647
+ actual_right_dist_atlas = size_atlas[1] - (rect_atlas[0] + rect_atlas[2])
648
+ actual_bottom_dist_atlas = size_atlas[0] - (rect_atlas[1] + rect_atlas[3])
649
+
650
+ left_dist_atlas = rect_image[0] * x_factor
651
+ right_dist_atlas = actual_right_dist_image * x_factor
652
+
653
+ top_dist_atlas = rect_image[1] * y_factor
654
+ bottom_dist_atlas = actual_bottom_dist_image * y_factor
655
+
656
+ if left_dist_atlas <= rect_atlas[0]:
657
+ atlas_corner_x = int(rect_atlas[0] - left_dist_atlas)
658
+ image_corner_x = 0
659
+ else:
660
+ atlas_corner_x = 0
661
+ left_dist_image = rect_atlas[0] / x_factor
662
+ image_corner_x = int(rect_image[0] - left_dist_image)
663
+
664
+ if right_dist_atlas <= actual_right_dist_atlas:
665
+ atlas_right_side = size_atlas[1] - (actual_right_dist_atlas - right_dist_atlas)
666
+ atlas_width = int(atlas_right_side - atlas_corner_x)
667
+ image_width = size_image[1] - image_corner_x
668
+ else:
669
+ atlas_width = size_atlas[1] - atlas_corner_x
670
+ right_dist_image = actual_right_dist_atlas / x_factor
671
+ image_width = int(
672
+ size_image[1]
673
+ - image_corner_x
674
+ - (actual_right_dist_image - right_dist_image)
675
+ )
676
+
677
+ if top_dist_atlas <= rect_atlas[1]:
678
+ atlas_corner_y = int(rect_atlas[1] - top_dist_atlas)
679
+ image_corner_y = 0
680
+ else:
681
+ atlas_corner_y = 0
682
+ top_dist_image = rect_atlas[1] / y_factor
683
+ image_corner_y = int(rect_image[1] - top_dist_image)
684
+
685
+ if bottom_dist_atlas <= actual_bottom_dist_atlas:
686
+ atlas_height = int(
687
+ size_atlas[0]
688
+ - atlas_corner_y
689
+ - (actual_bottom_dist_atlas - bottom_dist_atlas)
690
+ )
691
+ image_height = size_image[0] - image_corner_y
692
+ else:
693
+ atlas_height = size_atlas[0] - atlas_corner_y
694
+ bottom_dist_image = actual_bottom_dist_atlas / y_factor
695
+ image_height = int(
696
+ size_image[0]
697
+ - image_corner_y
698
+ - (actual_bottom_dist_image - bottom_dist_image)
699
+ )
700
+
701
+ atlas_rect = (atlas_corner_x, atlas_corner_y, atlas_width, atlas_height)
702
+ image_rect = (image_corner_x, image_corner_y, image_width, image_height)
703
+
704
+ return atlas_rect, image_rect
705
+
706
+
707
+ def get_corner_line_from_rect(rect):
708
+ corners = [
709
+ [rect[0], rect[1]],
710
+ [rect[0] + rect[2] - 1, rect[1]],
711
+ [rect[0] + rect[2] - 1, rect[1] + rect[3] - 1],
712
+ [rect[0], rect[1] + rect[3] - 1],
713
+ ]
714
+
715
+ lines = np.asarray(
716
+ [
717
+ [corners[0], corners[1]],
718
+ [corners[1], corners[2]],
719
+ [corners[3], corners[2]],
720
+ [corners[0], corners[3]],
721
+ ]
722
+ )
723
+
724
+ return corners, lines
725
+
726
+
727
+ def make_label_rgb_img(label_img, lut):
728
+ fimg = np.dstack([label_img, label_img, label_img])
729
+ unique_label = np.unique(label_img).astype(int)
730
+ for ind in np.unique(unique_label):
731
+ if ind == 0:
732
+ continue
733
+ loc = np.where(label_img == ind)
734
+ # print(lut[ind])
735
+ fimg[loc[0], loc[1], 0] = lut[ind][0]
736
+ fimg[loc[0], loc[1], 1] = lut[ind][1]
737
+ fimg[loc[0], loc[1], 2] = lut[ind][2]
738
+ return fimg.astype("uint8")
739
+
740
+
741
+ def make_contour_img(lable_img):
742
+ unique_label = np.unique(lable_img).astype("int")
743
+ img_size = lable_img.shape
744
+ contour_img = np.zeros(img_size, "uint8")
745
+ for label_ind in unique_label:
746
+ if label_ind == 0:
747
+ continue
748
+ temp = np.zeros(img_size, "uint8")
749
+ temp[lable_img == label_ind] = 1
750
+ ct, hc = cv2.findContours(
751
+ image=temp, mode=cv2.RETR_TREE, method=cv2.CHAIN_APPROX_NONE
752
+ )
753
+ for j in range(len(ct)):
754
+ da_contour = ct[j].copy()
755
+ da_shp = da_contour.shape
756
+ da_contour = np.reshape(da_contour, (da_shp[0], da_shp[2]))
757
+ contour_img[da_contour[:, 1], da_contour[:, 0]] = 1
758
+ return contour_img
759
+
760
+
761
+ def get_tri_lines(rect, pnts):
762
+ # print(rect)
763
+ subdiv = cv2.Subdiv2D(rect)
764
+ for p in pnts:
765
+ # print(p)
766
+ subdiv.insert((int(p[0]), int(p[1])))
767
+ edge_list = subdiv.getEdgeList()
768
+ lines_list = []
769
+ # special_pnt = []
770
+ for el in edge_list:
771
+ pt1 = [el[0], el[1]]
772
+ pt2 = [el[2], el[3]]
773
+ if rect_contains(rect, pt1) and rect_contains(rect, pt2):
774
+ lines_list.append(el)
775
+ # else:
776
+ # if not rect_contains(rect, pt1) and pt1 not in special_pnt:
777
+ # special_pnt.append(pt1)
778
+ # if not rect_contains(rect, pt2) and pt2 not in special_pnt:
779
+ # special_pnt.append(pt2)
780
+ return lines_list # , special_pnt
781
+
782
+
783
+ # czi_img = image_file.data['scene 0'].copy()
784
+ # channel_hsv = image_file.hsv_colors
785
+ # temp_img = merge_channels_into_single_img(czi_img, channel_hsv)
786
+
787
+
788
+ def gamma_correction(src, gamma):
789
+ inv_gamma = 1 / gamma
790
+
791
+ table = [((i / 255) ** inv_gamma) * 255 for i in range(256)]
792
+ table = np.array(table, np.uint8)
793
+
794
+ return cv2.LUT(src, table)
795
+
796
+
797
+ def get_lower_val(val, tol, lim):
798
+ lower_val = val - tol if tol < val else lim
799
+ return lower_val
800
+
801
+
802
+ def get_upper_val(val, tol, lim):
803
+ upper_val = val + tol
804
+ upper_val = upper_val if upper_val <= lim else lim
805
+ return upper_val
806
+
807
+
808
+ def get_bound_color(color, tol, level, mode):
809
+ tol = float(tol)
810
+ if mode == "gray":
811
+ lower_val = get_lower_val(color, tol, 0)
812
+ upper_val = get_upper_val(color, tol, level)
813
+ elif mode == "hsv":
814
+ lower_val = [get_lower_val(color[0], 1.0, 0)]
815
+ upper_val = [get_upper_val(color[0], 1.0, 180)]
816
+ for i in range(1, 3):
817
+ lower_val.append(get_lower_val(color[i], tol, 0))
818
+ upper_val.append(get_upper_val(color[i], tol, 255))
819
+ else:
820
+ lower_val = []
821
+ upper_val = []
822
+ for i in range(3):
823
+ lower_val.append(get_lower_val(color[i], tol, 0))
824
+ upper_val.append(get_upper_val(color[i], tol, level))
825
+ return lower_val, upper_val
826
+
827
+
828
+ # ----------------------------------------------------------------------------------
829
+ # ----------------------------------------------------------------------------------
830
+
831
+
832
+ def get_statusbar_style(col):
833
+ style = (
834
+ "background-color: #323232;"
835
+ " color: {}; border-top: 1px solid #272727; "
836
+ "padding-left: 30px;".format(col)
837
+ )
838
+ return style
839
+
840
+
841
+ def rotate(image, angle, img_center=None, scale=1.0):
842
+ (h, w) = image.shape[:2]
843
+
844
+ if img_center is None:
845
+ img_center = (w // 2, h // 2)
846
+
847
+ rot_mat = cv2.getRotationMatrix2D(img_center, angle, scale)
848
+ rotated_img = cv2.warpAffine(image, rot_mat, (w, h))
849
+
850
+ return rotated_img
851
+
852
+
853
+ def rotate_bound(image, angle):
854
+ (h, w) = image.shape[:2]
855
+ (center_x, center_y) = (w / 2, h / 2)
856
+
857
+ rot_mat = cv2.getRotationMatrix2D((center_x, center_y), -angle, 1.0)
858
+ cos = np.abs(rot_mat[0, 0])
859
+ sin = np.abs(rot_mat[0, 1])
860
+
861
+ bound_w = int((h * sin) + (w * cos))
862
+ bound_h = int((h * cos) + (w * sin))
863
+
864
+ rot_mat[0, 2] += (bound_w / 2) - center_x
865
+ rot_mat[1, 2] += (bound_h / 2) - center_y
866
+
867
+ return cv2.warpAffine(image, rot_mat, (bound_w, bound_h))
868
+
869
+
870
+ def center_resize(img, dim):
871
+ img_shape = img.shape
872
+ width, height = img_shape[1], img_shape[0]
873
+ scale_factor = np.min(np.array([dim[0] / width, dim[1] / height]))
874
+ resize_dim = (int(width * scale_factor), int(height * scale_factor))
875
+ resize_img = cv2.resize(img, resize_dim, interpolation=cv2.INTER_LINEAR)
876
+
877
+ y = int(0.5 * (dim[0] - resize_dim[0]))
878
+ x = int(0.5 * (dim[1] - resize_dim[1]))
879
+
880
+ if len(img_shape) == 3:
881
+ center_img = np.zeros((dim[1], dim[0], img.shape[2])).astype(img.dtype)
882
+ else:
883
+ center_img = np.zeros((dim[1], dim[0])).astype(img.dtype)
884
+
885
+ center_img[x : (x + resize_dim[1]), y : (y + resize_dim[0])] = resize_img
886
+
887
+ return center_img
888
+
889
+
890
+ def get_tb_size(img_size):
891
+ scale_factor = np.max(np.ravel(img_size) / 80)
892
+ tb_size = (int(img_size[1] / scale_factor), int(img_size[0] / scale_factor))
893
+ return tb_size
894
+
895
+
896
+ def get_slice_atlas_coord(points, cut, size, width, height, distance, origin):
897
+ """
898
+
899
+ :param points: pnts on image
900
+ :param cut: the cut of slice image
901
+ :param size: the size (height, width) of slice image in pixel
902
+ :param width: width of image in mm
903
+ :param height: height of image in mm
904
+ :param distance: distance of slice with respect to Bregma in mm
905
+ :param origin: the coord of bregma on the current slice image
906
+ :return:
907
+ """
908
+ width_factor = width / size[1] * 1000
909
+ height_factor = height / size[0] * 1000
910
+ if cut == "Coronal":
911
+ y_val = np.repeat(distance * 1000, len(points))
912
+ x_val = (points[:, 0] - origin[0]) * width_factor
913
+ z_val = (points[:, 1] - origin[1]) * height_factor
914
+ elif cut == "Sagittal":
915
+ x_val = np.repeat(distance * 1000, len(points))
916
+ y_val = (points[:, 0] - origin[0]) * width_factor
917
+ z_val = (points[:, 1] - origin[1]) * height_factor
918
+ else:
919
+ z_val = np.repeat(distance * 1000, len(points))
920
+ y_val = (points[:, 0] - origin[0]) * width_factor
921
+ x_val = (points[:, 1] - origin[1]) * height_factor
922
+ return x_val, y_val, z_val
923
+
924
+
925
+ def delete_points_inside_eraser(points, ct, r):
926
+ x_min, y_min, x_max, y_max = ct[0] - r, ct[1] - r, ct[0] + r, ct[1] + r
927
+ x_bool = np.logical_and(points[:, 0] <= x_max, points[:, 0] >= x_min)
928
+ y_bool = np.logical_and(points[:, 1] <= y_max, points[:, 1] >= y_min)
929
+ chk_inds = np.where(np.logical_and(x_bool, y_bool))[0]
930
+ if len(chk_inds) == 0:
931
+ return None, None
932
+ chk_pnt = points[chk_inds]
933
+ dist = np.sum(np.power(chk_pnt - ct, 2), 1)
934
+ del_ind = np.where(dist < np.power(r, 2))[0]
935
+ if len(del_ind) == 0:
936
+ return None, None
937
+ real_del_ind = chk_inds[del_ind]
938
+ remain_inds = np.zeros(len(points)) < 1
939
+ remain_inds[real_del_ind] = False
940
+ remain_points = points[remain_inds]
941
+ return remain_points, real_del_ind
942
+
943
+
944
+ def interpolate_contour_points(points):
945
+ if not np.all(points[-1] == points[0]):
946
+ points[:, 0] = np.r_[points[:, 0], points[:, 0]]
947
+ points[:, 1] = np.r_[points[:, 1], points[:, 1]]
948
+
949
+ tck = splprep([points[:, 0], points[:, 1]], s=0, per=True)
950
+
951
+ xi, yi = splev(np.linspace(0, 1, 1000), tck[0])
952
+ return xi, yi
953
+
954
+
955
+ def create_vis_img(size, point_data, color, vis_type="p", closed=False):
956
+ if isinstance(point_data, list):
957
+ point_data = np.asarray(point_data).astype(int)
958
+ else:
959
+ point_data = point_data.astype(int)
960
+ img = np.zeros((size[0], size[1], 3), "uint8")
961
+ da_color = (int(color[0]), int(color[1]), int(color[2]))
962
+ if vis_type == "p":
963
+ for i in range(len(point_data)):
964
+ cv2.circle(
965
+ img,
966
+ (int(point_data[i][0]), int(point_data[i][1])),
967
+ radius=5,
968
+ color=da_color,
969
+ thickness=-1,
970
+ )
971
+ else:
972
+ if closed:
973
+ cv2.fillPoly(img, pts=[point_data], color=da_color)
974
+ else:
975
+ for i in range(len(point_data) - 1):
976
+ cv2.line(
977
+ img,
978
+ (int(point_data[i][0]), int(point_data[i][1])),
979
+ (int(point_data[i + 1][0]), int(point_data[i + 1][1])),
980
+ color=da_color,
981
+ thickness=8,
982
+ )
983
+ return img
984
+
985
+
986
+ def color_vis_img(img, color):
987
+ temp = np.zeros((img.shape[0], img.shape[1], 3), "uint8")
988
+ temp[img != 0, 0] = color[0]
989
+ temp[img != 0, 1] = color[1]
990
+ temp[img != 0, 2] = color[2]
991
+ return temp
992
+
993
+
994
+ def check_loaded_project(project_dict):
995
+ required_keys = {
996
+ "atlas_path",
997
+ "img_path",
998
+ "current_atlas",
999
+ "num_windows",
1000
+ "probe_settings",
1001
+ "probe_type",
1002
+ "np_onside",
1003
+ "processing_slice",
1004
+ "processing_img",
1005
+ "overlay_img",
1006
+ "atlas_control",
1007
+ "img_ctrl_data",
1008
+ "setting_data",
1009
+ "tool_data",
1010
+ "layer_data",
1011
+ "working_img_data",
1012
+ "working_atlas_data",
1013
+ "object_data",
1014
+ }
1015
+ # ``probe_type`` was present only in early project files.
1016
+ required_keys.discard("probe_type")
1017
+ return isinstance(project_dict, dict) and required_keys.issubset(project_dict)
1018
+
1019
+
1020
+ def check_bounding_contains(points, size):
1021
+ points = np.asarray(points)
1022
+ if points.ndim != 2 or points.shape[1] != 2 or len(points) == 0:
1023
+ return False
1024
+ return coordinates_in_bounds(points, (size[1], size[0]))
1025
+
1026
+
1027
+ def obj_data_to_mesh3d(filename):
1028
+ vertices = []
1029
+ faces = []
1030
+
1031
+ with open(filename, "r") as objf:
1032
+ for line in objf:
1033
+ slist = line.split()
1034
+ if slist:
1035
+ if slist[0] == "v":
1036
+ vertex = np.array(slist[1:], dtype=float)
1037
+ vertices.append(vertex)
1038
+ elif slist[0] == "f":
1039
+ face = []
1040
+ for k in range(1, len(slist)):
1041
+ face.append(
1042
+ [int(s) for s in slist[k].replace("//", "/").split("/")]
1043
+ )
1044
+ if len(face) > 3: # triangulate the n-polyonal face, n>3
1045
+ faces.extend(
1046
+ [
1047
+ [face[0][0] - 1, face[k][0] - 1, face[k + 1][0] - 1]
1048
+ for k in range(1, len(face) - 1)
1049
+ ]
1050
+ )
1051
+ else:
1052
+ faces.append([face[j][0] - 1 for j in range(len(face))])
1053
+ else:
1054
+ pass
1055
+
1056
+ return np.array(vertices), np.array(faces)
1057
+
1058
+
1059
+ def make_atlas_label_contour(atlas_folder, segmentation_data):
1060
+ sagital_contour_img = np.zeros(segmentation_data.shape, "i")
1061
+ coronal_contour_img = np.zeros(segmentation_data.shape, "i")
1062
+ horizontal_contour_img = np.zeros(segmentation_data.shape, "i")
1063
+
1064
+ # pre-process boundary
1065
+ for i in range(len(segmentation_data)):
1066
+ da_slice = segmentation_data[i, :, :].copy()
1067
+ contour_img = make_contour_img(da_slice)
1068
+ sagital_contour_img[i, :, :] = contour_img
1069
+
1070
+ for i in range(segmentation_data.shape[1]):
1071
+ da_slice = segmentation_data[:, i, :].copy()
1072
+ contour_img = make_contour_img(da_slice)
1073
+ coronal_contour_img[:, i, :] = contour_img
1074
+
1075
+ for i in range(segmentation_data.shape[2]):
1076
+ da_slice = segmentation_data[:, :, i].copy()
1077
+ contour_img = make_contour_img(da_slice)
1078
+ horizontal_contour_img[:, :, i] = contour_img
1079
+
1080
+ boundary = {
1081
+ "s_contour": sagital_contour_img,
1082
+ "c_contour": coronal_contour_img,
1083
+ "h_contour": horizontal_contour_img,
1084
+ }
1085
+
1086
+ bnd = {"data": boundary}
1087
+
1088
+ outfile_ct = open(os.path.join(atlas_folder, "contour_pre_made.pkl"), "wb")
1089
+ pickle.dump(bnd, outfile_ct)
1090
+ outfile_ct.close()
1091
+
1092
+ return boundary
1093
+
1094
+
1095
+ def get_angle_two_vector(vec1, vec2):
1096
+ """
1097
+ in 2d
1098
+ :param vec1:
1099
+ :param vec2:
1100
+ :return:
1101
+ """
1102
+
1103
+ vec = np.array([-vec2[1], vec2[0]])
1104
+ b_coord = np.dot(vec1, vec2)
1105
+ p_coord = np.dot(vec1, vec)
1106
+ da_ang = np.arctan2(p_coord, b_coord)
1107
+
1108
+ return da_ang
1109
+
1110
+
1111
+ def rotate_base_points(data, base_loc):
1112
+ temp = np.stack([base_loc, np.repeat(0, len(base_loc))], axis=1)
1113
+ vec1 = data[1] - data[0]
1114
+ vec2 = np.array([0, 1])
1115
+ ang = get_angle_two_vector(vec1, vec2)
1116
+ rotm = np.array([[np.cos(ang), -np.sin(ang)], [np.sin(ang), np.cos(ang)]])
1117
+ base_pnt = np.dot(rotm, temp.T).T
1118
+ start_pnt = base_pnt + data[0]
1119
+ end_pnt = base_pnt + data[1]
1120
+ return start_pnt, end_pnt
1121
+
1122
+
1123
+ def get_cell_count(cell_layer_index):
1124
+ cell_count = [0 for _ in range(5)]
1125
+ cell_layer_index = np.ravel(cell_layer_index)
1126
+ for i in range(5):
1127
+ cell_count[i] = np.sum(cell_layer_index == i)
1128
+ return cell_count
1129
+
1130
+
1131
+ def load_point_data(data_file_path):
1132
+ file_basename = os.path.basename(data_file_path)
1133
+ file_name, file_ext = os.path.splitext(file_basename)
1134
+ msg = None
1135
+ data = None
1136
+ try:
1137
+ if file_ext == ".npy":
1138
+ data = np.load(data_file_path, allow_pickle=False)
1139
+ elif file_ext == ".pkl":
1140
+ data, msg = load_driftlessmap_file(data_file_path)
1141
+ if msg is not None:
1142
+ return data, msg
1143
+ except (
1144
+ IOError,
1145
+ OSError,
1146
+ ValueError,
1147
+ KeyError,
1148
+ IndexError,
1149
+ pickle.PickleError,
1150
+ pickle.UnpicklingError,
1151
+ ):
1152
+ msg = "Can not open atlas axis information file, please check the Tutorial on GitHub."
1153
+ return data, msg
1154
+
1155
+ if not isinstance(data, np.ndarray):
1156
+ msg = "Data is not numpy ndarray, please check the Tutorial on GitHub."
1157
+ return data, msg
1158
+
1159
+ data_shape = data.shape
1160
+ if len(data_shape) != 2:
1161
+ msg = "Data has wrong size, please check the Tutorial on GitHub."
1162
+ return data, msg
1163
+
1164
+ if data_shape[1] != 3:
1165
+ msg = "Data has wrong size, please check the Tutorial on GitHub."
1166
+ return data, msg
1167
+
1168
+ return data, msg