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.
- driftlessmap/__init__.py +16 -0
- driftlessmap/__main__.py +5 -0
- driftlessmap/about.py +24 -0
- driftlessmap/allen_downloader.py +908 -0
- driftlessmap/app.py +8085 -0
- driftlessmap/atlas_downloader.py +370 -0
- driftlessmap/atlas_loader.py +526 -0
- driftlessmap/atlas_processor.py +784 -0
- driftlessmap/atlas_transform.py +111 -0
- driftlessmap/atlas_view.py +1435 -0
- driftlessmap/cell_detection.py +27 -0
- driftlessmap/coordinate_validation.py +19 -0
- driftlessmap/czi_reader.py +236 -0
- driftlessmap/data/WHS_atlas_labels.pkl +0 -0
- driftlessmap/data/allen_mice_atlas_labels.pkl +0 -0
- driftlessmap/data/atlas_labels.pkl +0 -0
- driftlessmap/data/query.csv +1328 -0
- driftlessmap/download_utils.py +85 -0
- driftlessmap/herbs.png +0 -0
- driftlessmap/icons/backward.svg +15 -0
- driftlessmap/icons/dot.svg +11 -0
- driftlessmap/icons/down-arrow.svg +10 -0
- driftlessmap/icons/fast_backward.svg +14 -0
- driftlessmap/icons/fast_forward.svg +14 -0
- driftlessmap/icons/forward.svg +14 -0
- driftlessmap/icons/layers/add.png +0 -0
- driftlessmap/icons/layers/ai.png +0 -0
- driftlessmap/icons/layers/eye_off.png +0 -0
- driftlessmap/icons/layers/eye_on.png +0 -0
- driftlessmap/icons/layers/eye_white.png +0 -0
- driftlessmap/icons/layers/hi.png +0 -0
- driftlessmap/icons/layers/trash.png +0 -0
- driftlessmap/icons/object.svg +22 -0
- driftlessmap/icons/sidebar/add.png +0 -0
- driftlessmap/icons/sidebar/atlascontrol.png +0 -0
- driftlessmap/icons/sidebar/atlascontrol.svg +32 -0
- driftlessmap/icons/sidebar/bnd.svg +14 -0
- driftlessmap/icons/sidebar/c_section.png +0 -0
- driftlessmap/icons/sidebar/c_section2.png +0 -0
- driftlessmap/icons/sidebar/cell.svg +24 -0
- driftlessmap/icons/sidebar/check.svg +9 -0
- driftlessmap/icons/sidebar/compare.svg +18 -0
- driftlessmap/icons/sidebar/contour.svg +14 -0
- driftlessmap/icons/sidebar/h_section.png +0 -0
- driftlessmap/icons/sidebar/info.svg +14 -0
- driftlessmap/icons/sidebar/layers.png +0 -0
- driftlessmap/icons/sidebar/layers.svg +23 -0
- driftlessmap/icons/sidebar/line.svg +10 -0
- driftlessmap/icons/sidebar/link.svg +18 -0
- driftlessmap/icons/sidebar/link_off.svg +18 -0
- driftlessmap/icons/sidebar/merge.svg +11 -0
- driftlessmap/icons/sidebar/object.svg +13 -0
- driftlessmap/icons/sidebar/probe.png +0 -0
- driftlessmap/icons/sidebar/probe.svg +23 -0
- driftlessmap/icons/sidebar/rotation_horizontal.svg +14 -0
- driftlessmap/icons/sidebar/rotation_vertical.svg +14 -0
- driftlessmap/icons/sidebar/s_section.png +0 -0
- driftlessmap/icons/sidebar/tool.png +0 -0
- driftlessmap/icons/sidebar/tool.svg +19 -0
- driftlessmap/icons/sidebar/trash.png +0 -0
- driftlessmap/icons/sidebar/tree_checked.svg +10 -0
- driftlessmap/icons/sidebar/treeview.png +0 -0
- driftlessmap/icons/sidebar/treeview.svg +10 -0
- driftlessmap/icons/sidebar/treeview2.png +0 -0
- driftlessmap/icons/sidebar/virus.svg +24 -0
- driftlessmap/icons/tdown.svg +16 -0
- driftlessmap/icons/toolbar/accept.svg +18 -0
- driftlessmap/icons/toolbar/accept2.svg +24 -0
- driftlessmap/icons/toolbar/aim.svg +44 -0
- driftlessmap/icons/toolbar/aim_not.svg +28 -0
- driftlessmap/icons/toolbar/anchor.svg +14 -0
- driftlessmap/icons/toolbar/anticlockwise_rotation.svg +12 -0
- driftlessmap/icons/toolbar/atlas_icon.png +0 -0
- driftlessmap/icons/toolbar/boundary_register.svg +18 -0
- driftlessmap/icons/toolbar/cancel.svg +32 -0
- driftlessmap/icons/toolbar/cell_select.svg +22 -0
- driftlessmap/icons/toolbar/cell_select_not.svg +12 -0
- driftlessmap/icons/toolbar/check.svg +9 -0
- driftlessmap/icons/toolbar/clockwise_rotation.svg +11 -0
- driftlessmap/icons/toolbar/closed_path.svg +16 -0
- driftlessmap/icons/toolbar/closed_path2 copy.svg +19 -0
- driftlessmap/icons/toolbar/closed_path2.svg +20 -0
- driftlessmap/icons/toolbar/eraser.png +0 -0
- driftlessmap/icons/toolbar/eraser.svg +19 -0
- driftlessmap/icons/toolbar/eye.svg +17 -0
- driftlessmap/icons/toolbar/eye_closed.svg +19 -0
- driftlessmap/icons/toolbar/fill.svg +12 -0
- driftlessmap/icons/toolbar/gps.svg +15 -0
- driftlessmap/icons/toolbar/h_flip.png +0 -0
- driftlessmap/icons/toolbar/handle.png +0 -0
- driftlessmap/icons/toolbar/image_icon.png +0 -0
- driftlessmap/icons/toolbar/image_icon.svg +25 -0
- driftlessmap/icons/toolbar/info.svg +14 -0
- driftlessmap/icons/toolbar/inpart.png +0 -0
- driftlessmap/icons/toolbar/inpart.svg +17 -0
- driftlessmap/icons/toolbar/lasso.png +0 -0
- driftlessmap/icons/toolbar/lasso.svg +14 -0
- driftlessmap/icons/toolbar/left90.png +0 -0
- driftlessmap/icons/toolbar/line.svg +10 -0
- driftlessmap/icons/toolbar/line_sites.svg +11 -0
- driftlessmap/icons/toolbar/linear_silicon.png +0 -0
- driftlessmap/icons/toolbar/linear_silicon.svg +88 -0
- driftlessmap/icons/toolbar/list.svg +14 -0
- driftlessmap/icons/toolbar/location.svg +14 -0
- driftlessmap/icons/toolbar/magic-wand.svg +16 -0
- driftlessmap/icons/toolbar/magic_white.png +0 -0
- driftlessmap/icons/toolbar/mask.svg +10 -0
- driftlessmap/icons/toolbar/match.svg +20 -0
- driftlessmap/icons/toolbar/matchbnd.svg +18 -0
- driftlessmap/icons/toolbar/matching.svg +36 -0
- driftlessmap/icons/toolbar/merge.svg +11 -0
- driftlessmap/icons/toolbar/move_down.png +0 -0
- driftlessmap/icons/toolbar/move_left.png +0 -0
- driftlessmap/icons/toolbar/move_right.png +0 -0
- driftlessmap/icons/toolbar/move_up.png +0 -0
- driftlessmap/icons/toolbar/moving.png +0 -0
- driftlessmap/icons/toolbar/multi-probe.svg +119 -0
- driftlessmap/icons/toolbar/multi_pencil.svg +23 -0
- driftlessmap/icons/toolbar/multi_probe.png +0 -0
- driftlessmap/icons/toolbar/object.svg +13 -0
- driftlessmap/icons/toolbar/open_path.svg +22 -0
- driftlessmap/icons/toolbar/outpart.png +0 -0
- driftlessmap/icons/toolbar/outpart.svg +26 -0
- driftlessmap/icons/toolbar/pencil.png +0 -0
- driftlessmap/icons/toolbar/pencil.svg +19 -0
- driftlessmap/icons/toolbar/plasso.png +0 -0
- driftlessmap/icons/toolbar/probe.svg +19 -0
- driftlessmap/icons/toolbar/radar.svg +32 -0
- driftlessmap/icons/toolbar/rotation.svg +45 -0
- driftlessmap/icons/toolbar/rotation_clockwise.svg +18 -0
- driftlessmap/icons/toolbar/rotation_counter_clockwise.svg +18 -0
- driftlessmap/icons/toolbar/ruler.svg +27 -0
- driftlessmap/icons/toolbar/separate_sites.svg +13 -0
- driftlessmap/icons/toolbar/single_pencil.svg +16 -0
- driftlessmap/icons/toolbar/toa.svg +11 -0
- driftlessmap/icons/toolbar/toa_delete.svg +36 -0
- driftlessmap/icons/toolbar/toaa.svg +11 -0
- driftlessmap/icons/toolbar/toh.svg +11 -0
- driftlessmap/icons/toolbar/toh_delete.svg +36 -0
- driftlessmap/icons/toolbar/tohh.svg +11 -0
- driftlessmap/icons/toolbar/trans.png +0 -0
- driftlessmap/icons/toolbar/trans.svg +16 -0
- driftlessmap/icons/toolbar/triangulation.svg +10 -0
- driftlessmap/icons/toolbar/two_window.png +0 -0
- driftlessmap/icons/toolbar/unmerge.svg +16 -0
- driftlessmap/icons/toolbar/v_flip.png +0 -0
- driftlessmap/icons/toolbar/virus.svg +24 -0
- driftlessmap/icons/toolbar/virus_register.svg +31 -0
- driftlessmap/icons/toolbar/vis2d.svg +29 -0
- driftlessmap/icons/toolbar/window2.png +0 -0
- driftlessmap/icons/toolbar/window3.png +0 -0
- driftlessmap/icons/toolbar/window4.png +0 -0
- driftlessmap/icons/tree_close.svg +14 -0
- driftlessmap/icons/tree_open.svg +14 -0
- driftlessmap/icons/up-arrow.svg +10 -0
- driftlessmap/image_curves.py +579 -0
- driftlessmap/image_reader.py +186 -0
- driftlessmap/image_stacks.py +359 -0
- driftlessmap/image_view.py +646 -0
- driftlessmap/images_reader.py +5 -0
- driftlessmap/label_tree.py +278 -0
- driftlessmap/layer_validation.py +25 -0
- driftlessmap/layers_control.py +554 -0
- driftlessmap/main_window.ui +883 -0
- driftlessmap/movable_points.py +254 -0
- driftlessmap/obj_items.py +122 -0
- driftlessmap/object_control.py +1762 -0
- driftlessmap/persistence.py +376 -0
- driftlessmap/popup_message.py +16 -0
- driftlessmap/probe_csv.py +319 -0
- driftlessmap/probe_reconstruction.py +409 -0
- driftlessmap/probe_utiles.py +1442 -0
- driftlessmap/qss/atlas_view_group_box.qss +15 -0
- driftlessmap/qss/box_label.qss +7 -0
- driftlessmap/qss/channel_selector.qss +19 -0
- driftlessmap/qss/color_combo.qss +121 -0
- driftlessmap/qss/decor_label.qss +9 -0
- driftlessmap/qss/dialogs.qss +11 -0
- driftlessmap/qss/hidden_line_edit.qss +5 -0
- driftlessmap/qss/label_tree.qss +123 -0
- driftlessmap/qss/main_window.qss +243 -0
- driftlessmap/qss/menu_bar.qss +42 -0
- driftlessmap/qss/multi_handle_slider.qss +14 -0
- driftlessmap/qss/obj_ctrl_bottom_button.qss +29 -0
- driftlessmap/qss/object_text_button.qss +19 -0
- driftlessmap/qss/page_control.qss +36 -0
- driftlessmap/qss/rotation_button.qss +9 -0
- driftlessmap/qss/side_bar.qss +23 -0
- driftlessmap/qss/spinbox.qss +106 -0
- driftlessmap/qss/tabs.qss +211 -0
- driftlessmap/qss/tool_bar.qss +77 -0
- driftlessmap/resources.py +34 -0
- driftlessmap/roi_analysis.py +375 -0
- driftlessmap/run_driftlessmap.py +4 -0
- driftlessmap/slice_stacks.py +268 -0
- driftlessmap/slice_validation.py +20 -0
- driftlessmap/toolbox.py +569 -0
- driftlessmap/triangulation.py +517 -0
- driftlessmap/triangulation_points.py +108 -0
- driftlessmap/user_settings.py +92 -0
- driftlessmap/uuuuuu.py +1168 -0
- driftlessmap/version.py +3 -0
- driftlessmap/widgets_utils.py +140 -0
- driftlessmap/wtiles.py +715 -0
- driftlessmap-1.1.0.dist-info/METADATA +186 -0
- driftlessmap-1.1.0.dist-info/RECORD +210 -0
- driftlessmap-1.1.0.dist-info/WHEEL +5 -0
- driftlessmap-1.1.0.dist-info/entry_points.txt +2 -0
- driftlessmap-1.1.0.dist-info/licenses/LICENSE.txt +23 -0
- 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')
|