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
@@ -0,0 +1,526 @@
1
+ import os
2
+ from os.path import dirname, realpath, join
3
+ import sys
4
+ from sys import argv, exit
5
+ from pathlib import Path
6
+ import nrrd
7
+ import pickle
8
+ import csv
9
+ import nibabel as nib
10
+ import numpy as np
11
+ import pandas as pd
12
+ import cv2
13
+ from PyQt6.QtGui import *
14
+ from PyQt6.QtCore import *
15
+ from PyQt6.QtWidgets import *
16
+
17
+ from .uuuuuu import make_contour_img, make_atlas_label_contour
18
+ from .obj_items import render_volume, render_small_volume
19
+ from .atlas_transform import (
20
+ compact_atlas_volume,
21
+ compact_boundary_volume,
22
+ compact_label_volume,
23
+ normalize_atlas_volume,
24
+ prepare_atlas_mask,
25
+ )
26
+ from .persistence import load_legacy_pickle
27
+
28
+
29
+ def _make_label_info_data_waxholm_rat(label_file_path, excel_file_path):
30
+ # label_file_path = '..../WHS_SD_rat_atlas_v4.label'
31
+ # excel_file_path = '..../WHS SD rat brain atlas v4 labels for MBAT.xlsx'
32
+
33
+ xl_file = pd.ExcelFile(excel_file_path)
34
+ dfs = {sheet_name: xl_file.parse(sheet_name) for sheet_name in xl_file.sheet_names}
35
+ dfs_keys = list(dfs.keys())
36
+ if len(dfs_keys) != 1:
37
+ raise Exception('need to be only 1 sheet')
38
+
39
+ df = dfs[dfs_keys[0]]
40
+
41
+ index = []
42
+ level = []
43
+ name = []
44
+
45
+ for i in range(df.shape[0]):
46
+ da_line = df.iloc[i].values
47
+ for j in range(df.shape[1]):
48
+ if ~np.isnan(da_line[j]):
49
+ print(da_line[j])
50
+ index.append(da_line[j])
51
+ level.append(j)
52
+ name.append(da_line[j+1])
53
+ break
54
+
55
+ index = np.ravel(index).astype(int)
56
+ abv = df['Abbreviation'].values[:len(index)]
57
+ parent = df['Parent'].values[:len(index)].astype(int)
58
+
59
+ file = open(label_file_path, 'rb')
60
+ lines = file.readlines()
61
+ file.close()
62
+
63
+ for i in range(len(lines)):
64
+ da_line = lines[i].decode()
65
+ if da_line[0] == '#':
66
+ continue
67
+ start_line = i
68
+ break
69
+
70
+ lindex = []
71
+ red = []
72
+ green = []
73
+ blue = []
74
+ lname = []
75
+ for i in range(start_line, len(lines)):
76
+ da_line = lines[i].decode()
77
+ print(da_line)
78
+ da_elements = da_line.split('"')
79
+ da_numbers = da_elements[0].split()
80
+ lindex.append(int(da_numbers[0]))
81
+ red.append(int(da_numbers[1]))
82
+ green.append(int(da_numbers[2]))
83
+ blue.append(int(da_numbers[3]))
84
+ lname.append(da_elements[1])
85
+
86
+ lindex = np.ravel(lindex)
87
+ red = np.ravel(red)
88
+ green = np.ravel(green)
89
+ blue = np.ravel(blue)
90
+
91
+ colors = np.zeros((len(index), 3))
92
+ colors[:] = np.nan
93
+
94
+ for i in range(1, len(lname)):
95
+ print(i)
96
+ if lindex[i] not in index:
97
+ raise Exception('not matching')
98
+
99
+ for i in range(len(index)):
100
+ if index[i] > 600:
101
+ if index[i] == 1000:
102
+ colors[i] = np.array([50, 168, 82])
103
+ elif index[i] in [1001, 1050, 1002, 1003, 1004, 1005, 1006, 1051, 1007, 1008, 1009, 1010, 1011, 1012]:
104
+ colors[i] = np.array([255, 255, 255])
105
+ elif index[i] == 1048:
106
+ colors[i] = np.array([114, 126, 186])
107
+ elif index[i] == 1049:
108
+ colors[i] = np.array([16, 79, 24])
109
+ else:
110
+ colors[i] = np.array([128, 128, 128])
111
+ else:
112
+ da_ind = np.where(lindex == index[i])[0][0]
113
+ colors[i] = np.array([red[da_ind], green[da_ind], blue[da_ind]])
114
+
115
+ label = {}
116
+ label['index'] = index
117
+ label['color'] = colors.astype(int)
118
+ label['label'] = name
119
+ label['abbrev'] = abv
120
+ label['parent'] = parent
121
+ label['level_indicator'] = np.ravel(level)
122
+
123
+ outfile = open('atlas_labels.pkl', 'wb')
124
+ pickle.dump(label, outfile)
125
+ outfile.close()
126
+
127
+
128
+ def check_data_path_and_load(file_path):
129
+ data = None
130
+ _, file_extension = os.path.splitext(file_path)
131
+ file_extension = file_extension.lower()
132
+ if file_extension == '.pkl':
133
+ data, error = load_legacy_pickle(file_path)
134
+ success = error is None
135
+ elif file_extension == '.nrrd':
136
+ try:
137
+ data, _ = nrrd.read(file_path)
138
+ success = True
139
+ except Exception:
140
+ success = False
141
+ else:
142
+ try:
143
+ data_file = nib.load(file_path)
144
+ data = data_file.get_fdata()
145
+ success = True
146
+ except Exception:
147
+ success = False
148
+ return data, success
149
+
150
+
151
+
152
+ def check_atlas_file_path(atlas_folder, data_file=None, segmentation_file=None):
153
+ atlas_path = os.path.join(atlas_folder, data_file)
154
+ segmentation_path = os.path.join(atlas_folder, segmentation_file)
155
+
156
+ if not os.path.exists(atlas_path) or not os.path.exists(segmentation_path):
157
+ msg = 'atlas_path or segmentation_path not exist.'
158
+ msg_flag = 0
159
+ else:
160
+ msg = 'atlas path and segmentation path exist.'
161
+ msg_flag = 1
162
+
163
+ return msg, msg_flag, atlas_path, segmentation_path
164
+
165
+
166
+ def load_mask_file(atlas_folder, mask_file=None):
167
+ if mask_file is not None:
168
+ mask_path = os.path.join(atlas_folder, mask_file)
169
+ if os.path.exists(mask_path):
170
+ mask_data, mask_success = check_data_path_and_load(mask_path)
171
+ if not mask_success:
172
+ msg = 'Failed to load mask data.'
173
+ msg_flag = 0
174
+ mask_data = None
175
+ else:
176
+ if mask_data.ndim == 4 and mask_data.shape[-1] == 1:
177
+ mask_data = mask_data[..., 0]
178
+ if mask_data.ndim != 3:
179
+ msg = 'Mask data must be a 3-D volume.'
180
+ msg_flag = 0
181
+ mask_data = None
182
+ else:
183
+ msg = 'Mask data loaded successfully.'
184
+ msg_flag = 1
185
+ else:
186
+ msg = 'Mask path not exist.'
187
+ msg_flag = 0
188
+ mask_data = None
189
+ else:
190
+ msg = 'No mask data is needed.'
191
+ msg_flag = 1
192
+ mask_data = None
193
+
194
+ return msg, msg_flag, mask_data
195
+
196
+
197
+ def process_segmentation_data(atlas_folder, segmentation_path, mask_data):
198
+ segmentation_data, seg_success = check_data_path_and_load(segmentation_path)
199
+ if not seg_success:
200
+ msg = 'Failed to load segmentation data.'
201
+ msg_flag = 0
202
+ else:
203
+ if mask_data is not None:
204
+ try:
205
+ mask_data = prepare_atlas_mask(mask_data, segmentation_data.shape)
206
+ except ValueError as exc:
207
+ return str(exc), 0
208
+ # make segmentation with mask
209
+ for i in range(len(mask_data)):
210
+ segmentation_data[i][mask_data[i] == 0] = 0
211
+ segmentation_data = compact_label_volume(segmentation_data)
212
+
213
+ unique_label = np.unique(segmentation_data)
214
+
215
+ segment = {'data': segmentation_data, 'unique_label': unique_label}
216
+
217
+ outfile = open(os.path.join(atlas_folder, 'segment_pre_made.pkl'), 'wb')
218
+ pickle.dump(segment, outfile)
219
+ outfile.close()
220
+
221
+ msg = 'Segmentation data processed successfully.'
222
+ msg_flag = 1
223
+
224
+ return msg, msg_flag
225
+
226
+
227
+ def process_atlas_data(atlas_folder, atlas_path, mask_data,
228
+ bregma_coordinates=None, lambda_coordinates=None, voxel_size=None):
229
+ atlas_data, atlas_success = check_data_path_and_load(atlas_path)
230
+ if not atlas_success:
231
+ msg = 'Failed to load atlas volume data.'
232
+ msg_flag = 0
233
+ else:
234
+
235
+ new_atlas_data = atlas_data.copy()
236
+ if mask_data is not None:
237
+ try:
238
+ mask_data = prepare_atlas_mask(mask_data, new_atlas_data.shape)
239
+ except ValueError as exc:
240
+ return str(exc), 0
241
+ # make atlas with mask
242
+ for i in range(len(mask_data)):
243
+ new_atlas_data[i][mask_data[i] == 0] = 0
244
+ new_atlas_data = normalize_atlas_volume(new_atlas_data)
245
+
246
+ atlas_info = [
247
+ {'name': 'anterior', 'values': np.arange(new_atlas_data.shape[0]) * voxel_size, 'units': 'um'},
248
+ {'name': 'dorsal', 'values': np.arange(new_atlas_data.shape[1]) * voxel_size, 'units': 'um'},
249
+ {'name': 'right', 'values': np.arange(new_atlas_data.shape[2]) * voxel_size, 'units': 'um'},
250
+ {'vxsize': voxel_size,
251
+ 'Bregma': [bregma_coordinates[0], bregma_coordinates[1], bregma_coordinates[2]],
252
+ 'Lambda': [lambda_coordinates[0], lambda_coordinates[1], lambda_coordinates[2]]}
253
+ ]
254
+
255
+ atlas = {'data': new_atlas_data, 'info': atlas_info}
256
+
257
+ atlas_data = atlas['data']
258
+ atlas_info = atlas['info']
259
+
260
+ outfile = open(os.path.join(atlas_folder, 'atlas_pre_made.pkl'), 'wb')
261
+ pickle.dump(atlas, outfile)
262
+ outfile.close()
263
+
264
+ msg = 'Volume Atlas data processed successfully.'
265
+ msg_flag = 1
266
+
267
+ return msg, msg_flag
268
+
269
+
270
+ def process_contour_data(segmentation_data, dim_index=0):
271
+ contour_img = np.zeros(segmentation_data.shape, dtype=np.uint8)
272
+
273
+ # pre-process boundary
274
+ if dim_index == 0:
275
+ for i in range(segmentation_data.shape[dim_index]):
276
+ da_slice = segmentation_data[i, :, :].copy()
277
+ da_contour = make_contour_img(da_slice)
278
+ contour_img[i, :, :] = da_contour
279
+ elif dim_index == 1:
280
+ for i in range(segmentation_data.shape[dim_index]):
281
+ da_slice = segmentation_data[:, i, :].copy()
282
+ da_contour = make_contour_img(da_slice)
283
+ contour_img[:, i, :] = da_contour
284
+ else:
285
+ for i in range(segmentation_data.shape[dim_index]):
286
+ da_slice = segmentation_data[:, :, i].copy()
287
+ da_contour = make_contour_img(da_slice)
288
+ contour_img[:, :, i] = da_contour
289
+ return contour_img
290
+
291
+
292
+
293
+ # boundary = {'s_contour': sagital_contour_img,
294
+ # 'c_contour': coronal_contour_img,
295
+ # 'h_contour': horizontal_contour_img}
296
+ #
297
+ # bnd = {'data': boundary}
298
+ #
299
+ # outfile_ct = open(os.path.join(atlas_folder, 'contour_pre_made.pkl'), 'wb')
300
+ # pickle.dump(bnd, outfile_ct)
301
+ # outfile_ct.close()
302
+
303
+ def process_atlas_raw_data(atlas_folder, data_file=None, segmentation_file=None, mask_file=None,
304
+ bregma_coordinates=None, lambda_coordinates=None, voxel_size=None):
305
+ atlas_data, atlas_info, segmentation_data, unique_label, boundary = (
306
+ None, None, None, None, None
307
+ )
308
+
309
+ def failure(message):
310
+ return atlas_data, atlas_info, segmentation_data, unique_label, boundary, message
311
+
312
+ if not data_file or not segmentation_file:
313
+ return failure('Atlas and segmentation file names are required.')
314
+ if (
315
+ bregma_coordinates is None
316
+ or lambda_coordinates is None
317
+ or voxel_size is None
318
+ or voxel_size <= 0
319
+ ):
320
+ return failure('Bregma, Lambda, and a positive voxel size are required.')
321
+
322
+ atlas_path = os.path.join(atlas_folder, data_file)
323
+ segmentation_path = os.path.join(atlas_folder, segmentation_file)
324
+
325
+ if mask_file is not None:
326
+ mask_path = os.path.join(atlas_folder, mask_file)
327
+ if os.path.exists(mask_path):
328
+ mask_data, mask_success = check_data_path_and_load(mask_path)
329
+ if not mask_success:
330
+ return failure('Failed to load mask data.')
331
+ else:
332
+ return failure('Mask path does not exist.')
333
+ else:
334
+ mask_data = None
335
+
336
+ if not os.path.exists(atlas_path) or not os.path.exists(segmentation_path):
337
+ return failure('Atlas or segmentation path does not exist.')
338
+
339
+ # pre-process segmentation
340
+ segmentation_data, seg_success = check_data_path_and_load(segmentation_path)
341
+ if not seg_success:
342
+ return failure('Failed to load segmentation data.')
343
+
344
+ if np.asarray(segmentation_data).ndim != 3:
345
+ return failure('Segmentation data must be a 3-D volume.')
346
+
347
+ if mask_data is not None:
348
+ try:
349
+ mask_data = prepare_atlas_mask(mask_data, segmentation_data.shape)
350
+ except ValueError as exc:
351
+ return failure(str(exc))
352
+
353
+ if mask_data is not None:
354
+ # make segmentation with mask
355
+ for i in range(len(mask_data)):
356
+ segmentation_data[i][mask_data[i] == 0] = 0
357
+ segmentation_data = compact_label_volume(segmentation_data)
358
+
359
+ unique_label = np.unique(segmentation_data)
360
+
361
+ segment = {'data': segmentation_data, 'unique_label': unique_label}
362
+
363
+ # pre-process atlas
364
+ atlas_data, atlas_success = check_data_path_and_load(atlas_path)
365
+ if not atlas_success:
366
+ return failure('Failed to load atlas volume data.')
367
+
368
+ if np.asarray(atlas_data).shape != np.asarray(segmentation_data).shape:
369
+ return failure('Atlas and segmentation volumes must have matching shapes.')
370
+
371
+ new_atlas_data = np.asarray(atlas_data).copy()
372
+ if mask_data is not None:
373
+ # make atlas with mask
374
+ for i in range(len(mask_data)):
375
+ new_atlas_data[i][mask_data[i] == 0] = 0
376
+ new_atlas_data = normalize_atlas_volume(new_atlas_data)
377
+
378
+ atlas_info = [
379
+ {'name': 'anterior', 'values': np.arange(new_atlas_data.shape[0]) * voxel_size, 'units': 'um'},
380
+ {'name': 'dorsal', 'values': np.arange(new_atlas_data.shape[1]) * voxel_size, 'units': 'um'},
381
+ {'name': 'right', 'values': np.arange(new_atlas_data.shape[2]) * voxel_size, 'units': 'um'},
382
+ {'vxsize': voxel_size,
383
+ 'Bregma': [bregma_coordinates[0], bregma_coordinates[1], bregma_coordinates[2]],
384
+ 'Lambda': [lambda_coordinates[0], lambda_coordinates[1], lambda_coordinates[2]]}
385
+ ]
386
+
387
+ atlas = {'data': new_atlas_data, 'info': atlas_info}
388
+
389
+ atlas_data = atlas['data']
390
+ atlas_info = atlas['info']
391
+
392
+ with open(os.path.join(atlas_folder, 'segment_pre_made.pkl'), 'wb') as outfile:
393
+ pickle.dump(segment, outfile)
394
+ with open(os.path.join(atlas_folder, 'atlas_pre_made.pkl'), 'wb') as outfile:
395
+ pickle.dump(atlas, outfile)
396
+
397
+ boundary = make_atlas_label_contour(atlas_folder, segmentation_data)
398
+
399
+ msg = 'Atlas loaded successfully.'
400
+
401
+ return atlas_data, atlas_info, segmentation_data, unique_label, boundary, msg
402
+
403
+
404
+
405
+
406
+
407
+
408
+ class AtlasMeshProcessor(object):
409
+ def __init__(self, atlas_folder, atlas_data, segmentation_data, factor, level):
410
+ meshdata = render_volume(atlas_data, atlas_folder, factor=factor, level=level)
411
+
412
+ small_meshdata_list = render_small_volume(atlas_data, segmentation_data, atlas_folder,
413
+ factor=factor, level=level)
414
+
415
+
416
+ class AtlasLoader(object):
417
+ def __init__(self, atlas_folder, load_boundaries=True):
418
+ self.success = False
419
+ self.msg = ''
420
+ self.label_info = None
421
+ self.atlas_data = None
422
+ self.atlas_info = None
423
+ self.segmentation_data = None
424
+ self.unique_label = None
425
+ self.boundary = None
426
+
427
+ pre_made_atlas_path = os.path.join(atlas_folder, 'atlas_pre_made.pkl')
428
+ pre_made_segment_path = os.path.join(atlas_folder, 'segment_pre_made.pkl')
429
+ pre_made_boundary_path = os.path.join(atlas_folder, 'contour_pre_made.pkl')
430
+
431
+ pre_s_boundary_path = os.path.join(atlas_folder, 'sagital_contour_pre_made.pkl')
432
+ pre_c_boundary_path = os.path.join(atlas_folder, 'coronal_contour_pre_made.pkl')
433
+ pre_h_boundary_path = os.path.join(atlas_folder, 'horizontal_contour_pre_made.pkl')
434
+
435
+ pre_made_label_info_path = os.path.join(atlas_folder, 'atlas_labels.pkl')
436
+
437
+ required_paths = (
438
+ pre_made_label_info_path,
439
+ pre_made_atlas_path,
440
+ pre_made_segment_path,
441
+ )
442
+ if not all(os.path.exists(path) for path in required_paths):
443
+ self.msg = 'Please pre-process the raw data of your desire atlas.'
444
+ return
445
+
446
+ try:
447
+ self.label_info = self._load_pickle(pre_made_label_info_path)
448
+ atlas = self._load_pickle(pre_made_atlas_path)
449
+ self.atlas_data = compact_atlas_volume(atlas['data'])
450
+ self.atlas_info = atlas['info']
451
+ del atlas
452
+
453
+ segment = self._load_pickle(pre_made_segment_path)
454
+ self.segmentation_data = compact_label_volume(segment['data'])
455
+ self.unique_label = np.asarray(segment['unique_label'])
456
+ del segment
457
+ except (KeyError, TypeError, ValueError) as exc:
458
+ self.msg = 'Please re-process atlas and label segmentation file. {}'.format(exc)
459
+ return
460
+
461
+ if self.atlas_data.shape != self.segmentation_data.shape:
462
+ self.msg = 'Atlas and segmentation volumes have different shapes.'
463
+ return
464
+
465
+ if load_boundaries:
466
+ try:
467
+ if os.path.exists(pre_made_boundary_path):
468
+ boundary_data = self._load_pickle(pre_made_boundary_path)
469
+ raw_boundary = boundary_data['data']
470
+ self.boundary = {
471
+ key: compact_boundary_volume(raw_boundary[key])
472
+ for key in ('s_contour', 'c_contour', 'h_contour')
473
+ }
474
+ else:
475
+ boundary_paths = {
476
+ 's_contour': pre_s_boundary_path,
477
+ 'c_contour': pre_c_boundary_path,
478
+ 'h_contour': pre_h_boundary_path,
479
+ }
480
+ if not all(os.path.exists(path) for path in boundary_paths.values()):
481
+ self.msg = 'Please pre-process boundary file.'
482
+ return
483
+ self.boundary = {}
484
+ for key, path in boundary_paths.items():
485
+ raw_boundary = self._load_pickle(path)
486
+ self.boundary[key] = compact_boundary_volume(raw_boundary)
487
+ del raw_boundary
488
+
489
+ expected_boundary_keys = {'s_contour', 'c_contour', 'h_contour'}
490
+ if not isinstance(self.boundary, dict) or not expected_boundary_keys.issubset(
491
+ self.boundary
492
+ ):
493
+ raise ValueError('Boundary file is incomplete.')
494
+ if any(
495
+ np.asarray(self.boundary[key]).shape != self.segmentation_data.shape
496
+ for key in expected_boundary_keys
497
+ ):
498
+ raise ValueError('Boundary and segmentation volumes have different shapes.')
499
+ except (KeyError, TypeError, ValueError) as exc:
500
+ self.msg = 'Please re-process boundary file. {}'.format(exc)
501
+ self.boundary = None
502
+ return
503
+
504
+ self.success = True
505
+ self.msg = 'Atlas loaded successfully.'
506
+
507
+ @staticmethod
508
+ def _load_pickle(file_path):
509
+ data, error = load_legacy_pickle(file_path)
510
+ if error is not None:
511
+ raise ValueError(error)
512
+ return data
513
+
514
+
515
+
516
+
517
+
518
+
519
+
520
+
521
+
522
+
523
+
524
+ class AtlasMeshLoader(object):
525
+ def __init__(self, atlas_folder):
526
+ pre_made_meshdata_path = os.path.join(atlas_folder, 'atlas_meshdata.pkl')