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,646 @@
1
+ import colorsys
2
+ import os
3
+ import sys
4
+
5
+ import cv2
6
+ import copy
7
+ import pyqtgraph.functions as fn
8
+ import numpy as np
9
+ import pyqtgraph as pg
10
+ from PyQt6.QtWidgets import *
11
+ from PyQt6.QtGui import *
12
+ from PyQt6.QtCore import *
13
+ from pyqtgraph.Qt import QtGui, QtCore
14
+ import scipy.ndimage as ndi
15
+
16
+ from .image_stacks import ImageStacks
17
+ from .widgets_utils import ChannelSelector
18
+ from .image_curves import CurveWidget
19
+ from .uuuuuu import hsv2rgb, gamma_line, color_img, make_color_lut, get_corner_line_from_rect, \
20
+ rotate, rotate_bound, get_tb_size, read_qss_file
21
+ from .layer_validation import image_layer_matches
22
+ from .resources import resource_path
23
+
24
+
25
+ class ImagePageController(QWidget):
26
+ class SignalProxy(QObject):
27
+ sigPageChanged = pyqtSignal(object)
28
+
29
+ def __init__(self):
30
+ self._sigprox = ImagePageController.SignalProxy()
31
+ self.sig_page_changed = self._sigprox.sigPageChanged
32
+
33
+ QWidget.__init__(self)
34
+
35
+ # self.setStyleSheet(page_control_style)
36
+
37
+ self.max_val = None
38
+
39
+ self.page_slider = QSlider(Qt.Orientation.Horizontal)
40
+ self.page_slider.setMinimum(0)
41
+ self.page_slider.valueChanged.connect(self.slider_value_changed)
42
+
43
+ self.page_label = QLabel()
44
+ self.page_label.setFixedSize(50, 20)
45
+
46
+ self.page_left_btn = QPushButton()
47
+ self.page_left_btn.setIcon(QIcon(resource_path("icons/backward.svg")))
48
+ self.page_left_btn.setIconSize(QSize(16, 16))
49
+ self.page_left_btn.clicked.connect(self.left_btn_clicked)
50
+
51
+ self.page_right_btn = QPushButton()
52
+ self.page_right_btn.setIcon(QIcon(resource_path("icons/forward.svg")))
53
+ self.page_right_btn.setIconSize(QSize(16, 16))
54
+ self.page_right_btn.clicked.connect(self.right_btn_clicked)
55
+
56
+ page_ctrl_layout = QHBoxLayout()
57
+ page_ctrl_layout.setSpacing(0)
58
+ page_ctrl_layout.setContentsMargins(10, 5, 10, 5)
59
+ page_ctrl_layout.addWidget(self.page_left_btn)
60
+ page_ctrl_layout.addSpacing(10)
61
+ page_ctrl_layout.addWidget(self.page_slider)
62
+ page_ctrl_layout.addSpacing(5)
63
+ page_ctrl_layout.addWidget(self.page_label)
64
+ page_ctrl_layout.addWidget(self.page_right_btn)
65
+
66
+ self.setLayout(page_ctrl_layout)
67
+
68
+ def set_val(self, val):
69
+ self.page_slider.setValue(val)
70
+
71
+ def set_max(self, val):
72
+ self.max_val = val
73
+ self.page_slider.setMaximum(val)
74
+
75
+ def slider_value_changed(self):
76
+ val = self.page_slider.value()
77
+ self.page_label.setText(str(val))
78
+ self.sig_page_changed.emit(val)
79
+
80
+ def left_btn_clicked(self):
81
+ val = self.page_slider.value() - 1
82
+ if val < 0:
83
+ val = 0
84
+ self.set_val(val)
85
+
86
+ def right_btn_clicked(self):
87
+ val = self.page_slider.value() + 1
88
+ if val > self.max_val:
89
+ val = self.max_val
90
+ self.set_val(val)
91
+
92
+
93
+ class ImageView(QObject):
94
+ """
95
+ A collection of user interface elements bound together:
96
+ for histological images usage.
97
+
98
+ When set data into this object, the full image file is needed.
99
+ * the maximum channel number is 4, matching ZenBlue.
100
+ * scene_wrap, scale_wrap, img_stacks, curve_widget, chn_widget_wrap
101
+ * if image file is rgb, chn_widget_wrap will not show
102
+ * curve change for rgb ---> hsv on brightness channel
103
+ * curve change for not rgb ----> on the channel which is visible
104
+
105
+
106
+ """
107
+ class SignalProxy(QObject):
108
+ imageChanged = pyqtSignal() # id
109
+
110
+ def __init__(self):
111
+ self._sigprox = ImageView.SignalProxy()
112
+ self.sig_image_changed = self._sigprox.imageChanged
113
+
114
+ QObject.__init__(self)
115
+
116
+ # define the initials
117
+ self.image_file = None
118
+ self.processing_img = None
119
+ self.current_img = None
120
+ self.current_scale = None
121
+ self.img_size = None
122
+ self.tb_size = None
123
+ self.color_lut_list = []
124
+ self.original_lut_list = []
125
+ self.scene_index = 0
126
+ self.max_num_channels = 4
127
+ self.channel_visible = [False, False, False, False]
128
+ self.channel_color = [None, None, None, None]
129
+ self.color_combo_index = [-1, -1, -1, -1]
130
+
131
+ self.side_lines = None
132
+ self.corner_points = None
133
+ self.volume_img = None
134
+ self.display_img_index = 0
135
+
136
+ # scene control
137
+ sidebar_button_style = read_qss_file('qss/side_bar.qss')
138
+ self.check_scenes = QPushButton('Load ALL Scenes')
139
+ self.check_scenes.setStyleSheet(sidebar_button_style)
140
+ self.check_scenes.setCheckable(True)
141
+ self.scene_slider = QSlider(Qt.Orientation.Horizontal)
142
+ self.scene_slider.setMinimum(0)
143
+ self.scene_slider.setValue(0)
144
+ self.scene_slider.setTickPosition(QSlider.TickPosition.TicksBelow)
145
+ self.scene_slider.setTickInterval(1)
146
+ self.scene_slider.valueChanged.connect(self.scene_index_changed)
147
+ self.scene_label = QLabel('0/ 0')
148
+ self.scene_wrap = QFrame()
149
+ # self.scene_wrap.setFixedWidth(290)
150
+ scene_wrap_layout = QHBoxLayout(self.scene_wrap)
151
+ # scene_wrap_layout.setContentsMargins(0, 0, 0, 0)
152
+ # scene_wrap_layout.setSpacing(5)
153
+ scene_wrap_layout.addWidget(QLabel('Scene: '))
154
+ scene_wrap_layout.addWidget(self.scene_slider)
155
+ scene_wrap_layout.addWidget(self.scene_label)
156
+ # self.scene_wrap.setVisible(False)
157
+
158
+ # scale control
159
+ self.scale_slider = QSlider(Qt.Orientation.Horizontal)
160
+ self.scale_slider.setMinimum(1)
161
+ self.scale_slider.setMaximum(100)
162
+ self.scale_slider.setValue(10)
163
+ self.scale_slider.setSingleStep(10)
164
+ self.scale_slider.setTickInterval(10)
165
+ self.scale_slider.valueChanged.connect(self.scale_value_changed)
166
+ self.scale_slider.sliderReleased.connect(self.scale_slider_released)
167
+ self.scale_label = QLabel('{}%'.format(10))
168
+ self.scale_wrap = QFrame()
169
+ scale_wrap_layout = QHBoxLayout(self.scale_wrap)
170
+ scale_wrap_layout.addWidget(QLabel('Scale: '))
171
+ scale_wrap_layout.addWidget(self.scale_slider)
172
+ scale_wrap_layout.addWidget(self.scale_label)
173
+
174
+ # image stacks
175
+ self.img_stacks = ImageStacks()
176
+
177
+ # scene control
178
+ self.page_ctrl = ImagePageController()
179
+ self.page_ctrl.setVisible(False)
180
+ self.page_ctrl.sig_page_changed.connect(self.image_page_changed)
181
+
182
+ # curve widget
183
+ self.curve_widget = CurveWidget()
184
+ self.curve_widget.setEnabled(False)
185
+ self.curve_widget.setFixedHeight(280)
186
+ self.curve_widget.sig_table_changed.connect(self.image_curve_changed)
187
+ self.curve_widget.sig_reset.connect(self.image_curve_reset)
188
+ self.curve_widget.sig_line_type_changed.connect(self.image_curve_type_changed)
189
+
190
+ # channel buttons
191
+ self.chn_widget_wrap = QFrame()
192
+ self.chn_widget_wrap.setStyleSheet('QFrame{border: 1px solid #747a80; border-radius: 5px;}')
193
+ chn_widget_layout = QHBoxLayout(self.chn_widget_wrap)
194
+ self.chn_widget_list = []
195
+ for i in range(self.max_num_channels):
196
+ self.chn_widget_list.append(ChannelSelector())
197
+ self.chn_widget_list[i].set_channel_index(i)
198
+ self.chn_widget_list[i].sig_vis_channels.connect(self.set_channel_visible)
199
+ self.chn_widget_list[i].sig_change_color.connect(self.channel_color_changed)
200
+ chn_widget_layout.addWidget(self.chn_widget_list[i])
201
+ self.chn_widget_list[i].setVisible(False)
202
+ # self.chn_widget_wrap.setVisible(False)
203
+
204
+ self.outer_frame = QFrame()
205
+ outer_layout = QVBoxLayout(self.outer_frame)
206
+ outer_layout.setContentsMargins(0, 0, 0, 0)
207
+ outer_layout.setSpacing(0)
208
+ outer_layout.addWidget(self.check_scenes)
209
+ outer_layout.addWidget(self.scale_wrap)
210
+ outer_layout.addWidget(self.scene_wrap)
211
+ outer_layout.addWidget(self.curve_widget)
212
+ outer_layout.addSpacing(10)
213
+ outer_layout.addWidget(self.chn_widget_wrap)
214
+
215
+ def set_data(self, image_file):
216
+ if image_file.n_channels > self.max_num_channels:
217
+ raise ValueError(
218
+ 'DriftlessMap supports at most {} image channels.'.format(
219
+ self.max_num_channels
220
+ )
221
+ )
222
+ if self.image_file is not None:
223
+ self.page_ctrl.setVisible(False)
224
+ self.clear_image_stacks()
225
+ self.curve_widget.reset_pressed()
226
+ self.curve_widget.setEnabled(False)
227
+ for i in range(self.image_file.n_channels):
228
+ self.chn_widget_list[i].delete_item()
229
+ for i in range(self.max_num_channels):
230
+ self.channel_color[i] = None
231
+ self.channel_visible[i] = False
232
+ self.img_stacks.image_list[i].clear()
233
+ self.chn_widget_list[i].setVisible(False)
234
+ self.image_file = None
235
+ self.color_lut_list.clear()
236
+ self.original_lut_list.clear()
237
+ self.curve_widget.line_type_combo.setCurrentIndex(0)
238
+
239
+ self.image_file = image_file
240
+
241
+ if self.image_file.n_pages > 1:
242
+ self.page_ctrl.set_max(self.image_file.n_pages - 1)
243
+ self.page_ctrl.setVisible(True)
244
+ self.volume_img = copy.deepcopy(self.image_file.data['scene 0'])
245
+ init_page_number = int(0.5 * self.image_file.n_pages)
246
+ self.page_ctrl.set_val(init_page_number)
247
+ temp_data = self.volume_img[init_page_number, :, :].copy()
248
+ temp_data = [temp_data]
249
+ self.current_img = np.dstack(temp_data)
250
+ else:
251
+ self.volume_img = None
252
+ self.current_img = copy.deepcopy(self.image_file.data['scene 0'])
253
+
254
+ self.current_scale = self.image_file.scale['scene 0']
255
+
256
+ if self.image_file.n_scenes != 1:
257
+ self.scene_slider.setMaximum(self.image_file.n_scenes - 1)
258
+ self.scene_label.setText('1/{}'.format(self.image_file.n_scenes))
259
+ self.scene_wrap.setVisible(True)
260
+ else:
261
+ self.scene_wrap.setVisible(False)
262
+
263
+ if not self.image_file.is_czi:
264
+ self.scale_wrap.setVisible(False)
265
+ else:
266
+ self.scale_wrap.setVisible(True)
267
+
268
+ # set data to curves
269
+ self.set_curve_widgets() # get reasonable table
270
+ self.set_channel_widgets() # get initial color_lut_list for each layer
271
+
272
+ # set data to image stacks
273
+ self.set_data_to_img_stacks()
274
+ self.get_corner_and_lines()
275
+
276
+ def set_channel_widgets(self):
277
+ # set color and names to channels
278
+ self.chn_widget_wrap.setVisible(True)
279
+ for i in range(self.image_file.n_channels):
280
+ # get color look-up-table
281
+ self.channel_color[i] = copy.deepcopy(self.image_file.hsv_colors[i])
282
+ da_hsv_color = self.channel_color[i]
283
+ da_lut = make_color_lut(da_hsv_color, self.image_file.level + 1)
284
+ self.original_lut_list.append(da_lut)
285
+ self.color_lut_list.append(da_lut)
286
+ self.chn_widget_list[i].setVisible(True)
287
+ self.chn_widget_list[i].vis_btn.setText(self.image_file.channel_name[i])
288
+ self.chn_widget_list[i].add_item(self.channel_color[i])
289
+ self.channel_visible[i] = True
290
+ self.color_combo_index[i] = self.chn_widget_list[i].color_combo.currentIndex()
291
+
292
+ def set_curve_widgets(self):
293
+ self.curve_widget.setEnabled(True)
294
+ img_layers = self.current_img.copy()
295
+ self.curve_widget.set_data(img_layers, self.image_file.rgb_colors, self.image_file.level)
296
+
297
+ def channel_color_changed(self, col, ind):
298
+ da_lut = make_color_lut(col, self.curve_widget.gray_max + 1)
299
+ self.original_lut_list[ind] = da_lut.copy()
300
+ self.color_lut_list[ind] = da_lut[self.curve_widget.table_output[ind], :]
301
+ self.img_stacks.image_list[ind].setLevels(levels=(0, self.image_file.level))
302
+ self.img_stacks.image_list[ind].setLookupTable(self.color_lut_list[ind])
303
+ self.channel_color[ind] = col
304
+ self.curve_widget.curve_plot.change_hist_color(col, ind)
305
+ self.color_combo_index[ind] = self.chn_widget_list[ind].color_combo.currentIndex()
306
+
307
+ def set_channel_visible(self, vis, ind):
308
+ if np.sum(self.channel_visible) == 1:
309
+ vis_layer_ind = np.where(np.ravel(self.channel_visible))[0][0]
310
+ if vis_layer_ind == ind:
311
+ return
312
+ self.channel_visible[ind] = vis
313
+ self.img_stacks.image_list[ind].setVisible(vis)
314
+ self.curve_widget.set_channel_enable(ind, vis)
315
+
316
+ def channel_selector_reset(self):
317
+ for i in range(self.image_file.n_channels):
318
+ self.chn_widget_list[i].vis_btn.setChecked(False)
319
+ self.chn_widget_list[i].vis = True
320
+ self.chn_widget_list[i].set_checked(False)
321
+
322
+ def set_data_and_size(self, img_data):
323
+ self.img_stacks.set_data(img_data)
324
+ self.img_size = img_data.shape[:2]
325
+ print('image_view', self.img_size)
326
+ rect = (0, 0, self.img_size[1], self.img_size[0])
327
+ self.corner_points, self.side_lines = get_corner_line_from_rect(rect)
328
+ self.img_stacks.image_dict['tri_pnts'].set_range(self.img_size[1], self.img_size[0])
329
+ self.tb_size = get_tb_size(self.img_size)
330
+
331
+ def set_data_to_img_stacks(self):
332
+ self.set_data_and_size(self.current_img)
333
+ self.img_stacks.set_lut(self.color_lut_list, self.curve_widget.gray_max)
334
+
335
+ def get_corner_and_lines(self):
336
+ rect = (0, 0, self.img_size[1], self.img_size[0])
337
+ self.corner_points, self.side_lines = get_corner_line_from_rect(rect)
338
+ self.sig_image_changed.emit()
339
+
340
+ def image_page_changed(self, page_number):
341
+ self.display_img_index = page_number
342
+ temp_data = self.volume_img[page_number, :, :].copy()
343
+ temp_data = [temp_data]
344
+ self.current_img = np.dstack(temp_data)
345
+ self.img_stacks.set_data(self.current_img)
346
+
347
+ def scene_index_changed(self):
348
+ if self.image_file is None:
349
+ return
350
+ scene_index = self.scene_slider.value()
351
+ self.scene_label.setText('{}/{}'.format(scene_index + 1, self.image_file.n_scenes))
352
+ with pg.BusyCursor():
353
+ self.clear_image_stacks()
354
+ if 'scene {}'.format(scene_index) not in list(self.image_file.data.keys()):
355
+ scale = self.scale_slider.value()
356
+ scale_val = scale * 0.01
357
+ self.image_file.read_data(scale_val, scene_index=scene_index)
358
+ self.current_img = copy.deepcopy(self.image_file.data['scene {}'.format(scene_index)])
359
+ self.current_scale = self.image_file.scale['scene {}'.format(scene_index)]
360
+
361
+ if self.current_scale != self.scale_slider.value() * 0.01:
362
+ self.scale_slider.setValue(self.current_scale * 100)
363
+
364
+ self.img_size = self.current_img.shape[:2]
365
+ for i in range(self.image_file.n_channels):
366
+ self.img_stacks.image_list[i].clear()
367
+ self.img_stacks.image_dict['tri_pnts'].set_range(self.img_size[1], self.img_size[0])
368
+
369
+ self.channel_selector_reset()
370
+ self.curve_widget.curve_plot.reset_plot()
371
+
372
+ self.img_stacks.set_data(self.current_img)
373
+ self.img_stacks.set_lut(self.original_lut_list, self.image_file.level)
374
+ self.get_corner_and_lines()
375
+ self.set_curve_widgets()
376
+ # reset gamma and channels and black/white slider
377
+
378
+ def scale_value_changed(self):
379
+ scale = self.scale_slider.value()
380
+ self.scale_label.setText('{}%'.format(scale))
381
+
382
+ def scale_slider_released(self):
383
+ if self.image_file is None:
384
+ return
385
+ if self.image_file.is_czi:
386
+ self.clear_image_stacks()
387
+ scale = self.scale_slider.value()
388
+ scale_val = scale * 0.01
389
+ scene_index = self.scene_slider.value()
390
+ with pg.BusyCursor():
391
+ self.image_file.read_data(scale_val, scene_index)
392
+ self.current_img = copy.deepcopy(self.image_file.data['scene %d' % scene_index])
393
+ self.current_scale = self.image_file.scale['scene {}'.format(scene_index)]
394
+
395
+ self.img_size = self.current_img.shape[:2]
396
+ for i in range(self.image_file.n_channels):
397
+ self.img_stacks.image_list[i].clear()
398
+ self.img_stacks.image_dict['tri_pnts'].set_range(self.img_size[1], self.img_size[0])
399
+ self.set_data_to_img_stacks()
400
+ self.get_corner_and_lines()
401
+
402
+ def image_curve_changed(self, ev):
403
+ if self.current_img is None:
404
+ return
405
+ table = ev[0]
406
+ ind = ev[1]
407
+ lut_in = self.original_lut_list[ind].copy()
408
+ self.color_lut_list[ind] = lut_in[table, :]
409
+ self.img_stacks.image_list[ind].setLookupTable(self.color_lut_list[ind])
410
+ # table = table.astype(int)
411
+ # if self.image_file.pixel_type == 'rgb24':
412
+ # da_img = cv2.LUT(self.current_img.astype('uint8'), table)
413
+ # self.img_stacks.set_data(da_img)
414
+ # else:
415
+ # for i in range(self.image_file.n_channels):
416
+ # if self.channel_visible[i]:
417
+ # lut_in = self.color_lut_list[i].copy()
418
+ # self.color_lut_list[i] = lut_in[table, :]
419
+ # self.img_stacks.image_list[i].setLookupTable(self.color_lut_list[i])
420
+
421
+ def image_curve_type_changed(self):
422
+ """
423
+ signal function after change line type
424
+ set to the original 2 points linear type
425
+ """
426
+ if self.image_file is None:
427
+ return
428
+ for i in range(self.image_file.n_channels):
429
+ self.img_stacks.image_list[i].setLookupTable(self.original_lut_list[i])
430
+
431
+ def image_curve_reset(self):
432
+ """
433
+ signal function after press button 'Reset'
434
+ """
435
+ for i in range(self.image_file.n_channels):
436
+ self.channel_color[i] = self.image_file.hsv_colors[i]
437
+ for i in range(self.image_file.n_channels):
438
+ self.chn_widget_list[i].color_combo.setCurrentIndex(
439
+ len(self.chn_widget_list[i].color_combo.hsv_color_list) - 1)
440
+ self.curve_widget.curve_plot.change_hist_color(self.channel_color[i], i)
441
+ self.img_stacks.image_list[i].setLookupTable(self.original_lut_list[i])
442
+ self.color_lut_list = self.original_lut_list.copy()
443
+
444
+ def get_img_ctrl_data(self):
445
+ lut_points_data = []
446
+ for i in range(self.current_img.shape[2]):
447
+ lut_points_data.append(self.curve_widget.curve_plot.lut_points[i].data['pos'].copy())
448
+
449
+ data = {'current_img': self.current_img,
450
+ 'processing_img': self.processing_img,
451
+ 'current_scene': self.scene_slider.value(),
452
+ 'current_scale': self.scale_slider.value(),
453
+ 'channel_color': self.channel_color,
454
+ 'color_combo_index': self.color_combo_index,
455
+ 'original_lut_list': self.original_lut_list,
456
+ 'color_lut_list': self.color_lut_list,
457
+ 'gamma_vals': self.curve_widget.gamma,
458
+ 'table_output': self.curve_widget.table_output,
459
+ 'original_table': self.curve_widget.original_table,
460
+ 'line_type': self.curve_widget.line_type,
461
+ 'hist_data': self.curve_widget.curve_plot.hist_data,
462
+ 'lut_points_data': lut_points_data}
463
+ return data
464
+
465
+ def load_img_ctrl_data(self, img_ctrl_data):
466
+ self.current_img = img_ctrl_data['current_img']
467
+ self.current_scale = img_ctrl_data['current_scale']
468
+ self.channel_color = img_ctrl_data['channel_color']
469
+ self.color_combo_index = img_ctrl_data['color_combo_index']
470
+ self.processing_img = img_ctrl_data['processing_img']
471
+ # set data
472
+ # self.scene_wrap.setVisible(False)
473
+
474
+ self.scene_slider.blockSignals(True)
475
+ self.scene_slider.setValue(img_ctrl_data['current_scene'])
476
+ self.scene_label.setText('{}/{}'.format(img_ctrl_data['current_scene'] + 1, self.image_file.n_scenes))
477
+ self.scene_slider.blockSignals(False)
478
+
479
+ self.curve_widget.gamma = img_ctrl_data['gamma_vals']
480
+ self.curve_widget.table_output = img_ctrl_data['table_output']
481
+ self.curve_widget.original_table = img_ctrl_data['original_table']
482
+ self.curve_widget.line_type = img_ctrl_data['line_type']
483
+
484
+ self.curve_widget.line_type_combo.blockSignals(True)
485
+ self.curve_widget.line_type_combo.setCurrentText(self.curve_widget.line_type)
486
+ self.curve_widget.line_type_combo.blockSignals(False)
487
+
488
+ self.curve_widget.curve_plot.line_type = self.curve_widget.line_type
489
+ self.curve_widget.curve_plot.set_data(img_ctrl_data['hist_data'], self.image_file.rgb_colors,
490
+ self.image_file.level)
491
+
492
+ for i in range(self.image_file.n_channels):
493
+ self.curve_widget.curve_plot.change_hist_color(self.channel_color[i], i)
494
+ self.curve_widget.curve_plot.set_lut_line(self.curve_widget.table_output[i], i)
495
+ self.curve_widget.curve_plot.set_lut_points(img_ctrl_data['lut_points_data'][i], i)
496
+
497
+ for i in range(self.image_file.n_channels):
498
+ self.curve_widget.curve_plot.set_enable(i, True)
499
+ self.curve_widget.set_enable_induced_slider()
500
+
501
+ self.original_lut_list = img_ctrl_data['original_lut_list']
502
+ self.color_lut_list = img_ctrl_data['color_lut_list']
503
+
504
+ for i in range(self.image_file.n_channels):
505
+ self.chn_widget_list[i].blockSignals(True)
506
+ self.chn_widget_list[i].setVisible(True)
507
+ self.chn_widget_list[i].vis_btn.setChecked(False)
508
+ self.chn_widget_list[i].set_checked(False)
509
+ self.chn_widget_list[i].vis_btn.setText(self.image_file.channel_name[i])
510
+ self.chn_widget_list[i].color_combo.blockSignals(True)
511
+ self.chn_widget_list[i].add_item(self.image_file.hsv_colors[i])
512
+ self.chn_widget_list[i].color_combo.setCurrentIndex(self.color_combo_index[i])
513
+ self.chn_widget_list[i].color_combo.blockSignals(False)
514
+ self.channel_visible[i] = True
515
+ self.chn_widget_list[i].blockSignals(False)
516
+
517
+ self.original_lut_list = img_ctrl_data['original_lut_list']
518
+ self.color_lut_list = img_ctrl_data['color_lut_list']
519
+
520
+ # self.set_data_and_size(self.processing_img)
521
+
522
+ #
523
+ def check_img_process_layer_data(self, layer_dict):
524
+ if self.current_img is None or self.image_file is None:
525
+ return False
526
+ return image_layer_matches(
527
+ layer_dict,
528
+ self.current_img.shape[:2],
529
+ expected_level=self.image_file.level,
530
+ require_metadata=True,
531
+ )
532
+
533
+ def has_loaded_layer_the_same_size(self, layer_dict):
534
+ if self.current_img is None:
535
+ return False
536
+ return image_layer_matches(layer_dict, self.current_img.shape[:2])
537
+
538
+ def save_img_process_data(self):
539
+ data = {'data': self.processing_img,
540
+ 'level': self.image_file.level,
541
+ 'size': self.img_size}
542
+ return data
543
+
544
+ # clear image stacks
545
+ def clear_image_stacks(self):
546
+ valid_keys = ['img-overlay', 'overlay_contour', 'img-mask', 'circle_follow', 'lasso_path', 'img-virus',
547
+ 'img-contour', 'img-probe', 'img-cells', 'img-blob', 'img-drawing']
548
+
549
+ for da_key in valid_keys:
550
+ self.img_stacks.image_dict[da_key].clear()
551
+
552
+ # image rotation
553
+ def image_vertical_flip(self):
554
+ if self.image_file is None:
555
+ return
556
+ # if self.image_file.is_rgb:
557
+ # self.current_img = cv2.flip(self.current_img, 0)
558
+ # else:
559
+ for i in range(self.image_file.n_channels):
560
+ self.current_img[:, :, i] = cv2.flip(self.current_img[:, :, i], 0)
561
+ self.clear_image_stacks()
562
+ self.img_size = self.current_img.shape[:2]
563
+ self.img_stacks.image_dict['tri_pnts'].set_range(self.img_size[1], self.img_size[0])
564
+ self.img_stacks.set_data(self.current_img)
565
+
566
+ def image_horizon_flip(self):
567
+ if self.image_file is None:
568
+ return
569
+ # if self.image_file.is_rgb:
570
+ # self.current_img = cv2.flip(self.current_img, 1)
571
+ # else:
572
+ for i in range(self.image_file.n_channels):
573
+ self.current_img[:, :, i] = cv2.flip(self.current_img[:, :, i], 1)
574
+ self.clear_image_stacks()
575
+ self.img_stacks.set_data(self.current_img)
576
+ self.img_size = self.current_img.shape[:2]
577
+ self.img_stacks.image_dict['tri_pnts'].set_range(self.img_size[1], self.img_size[0])
578
+
579
+ def image_90_rotate(self):
580
+ if self.image_file is None:
581
+ return
582
+ temp = []
583
+ for i in range(self.image_file.n_channels):
584
+ self.img_stacks.image_list[i].clear()
585
+ temp.append(cv2.rotate(self.current_img[:, :, i], cv2.ROTATE_90_CLOCKWISE))
586
+ self.current_img = np.dstack(temp)
587
+ self.clear_image_stacks()
588
+ self.img_stacks.set_data(self.current_img)
589
+ self.img_size = self.current_img.shape[:2]
590
+ self.img_stacks.image_dict['tri_pnts'].set_range(self.img_size[1], self.img_size[0])
591
+ self.get_corner_and_lines()
592
+ # self.image_file.data['scene %d' % scene_index] = self.current_img.copy()
593
+ self.tb_size = np.flip(self.tb_size, 0)
594
+
595
+ def image_180_rotate(self):
596
+ if self.image_file is None:
597
+ return
598
+ # if self.image_file.is_rgb:
599
+ # self.current_img = cv2.rotate(self.current_img, cv2.ROTATE_180)
600
+ # else:
601
+ temp = []
602
+ for i in range(self.image_file.n_channels):
603
+ self.img_stacks.image_list[i].clear()
604
+ temp.append(cv2.rotate(self.current_img[:, :, i], cv2.ROTATE_180))
605
+ self.current_img = np.dstack(temp)
606
+ self.clear_image_stacks()
607
+ self.img_stacks.set_data(self.current_img)
608
+ self.img_size = self.current_img.shape[:2]
609
+ self.img_stacks.image_dict['tri_pnts'].set_range(self.img_size[1], self.img_size[0])
610
+
611
+ def image_90_counter_rotate(self):
612
+ if self.image_file is None:
613
+ return
614
+ # if self.image_file.is_rgb:
615
+ # self.current_img = cv2.rotate(self.current_img, cv2.ROTATE_90_COUNTERCLOCKWISE)
616
+ # else:
617
+ temp = []
618
+ for i in range(self.image_file.n_channels):
619
+ self.img_stacks.image_list[i].clear()
620
+ temp.append(cv2.rotate(self.current_img[:, :, i], cv2.ROTATE_90_COUNTERCLOCKWISE))
621
+ self.current_img = np.dstack(temp)
622
+ self.clear_image_stacks()
623
+ self.img_stacks.set_data(self.current_img)
624
+ self.img_size = self.current_img.shape[:2]
625
+ self.img_stacks.image_dict['tri_pnts'].set_range(self.img_size[1], self.img_size[0])
626
+ self.get_corner_and_lines()
627
+ self.tb_size = np.flip(self.tb_size, 0)
628
+
629
+ def image_1_rotate(self, rotate_direction):
630
+ if self.image_file is None:
631
+ return
632
+ if rotate_direction == 'clockwise':
633
+ rotation_angle = - 1
634
+ else:
635
+ rotation_angle = 1
636
+ temp = []
637
+ for i in range(self.image_file.n_channels):
638
+ temp.append(rotate(self.current_img[:, :, i], rotation_angle))
639
+ self.current_img = np.dstack(temp)
640
+ self.clear_image_stacks()
641
+ self.img_stacks.set_data(self.current_img)
642
+ self.img_size = self.current_img.shape[:2]
643
+ self.img_stacks.image_dict['tri_pnts'].set_range(self.img_size[1], self.img_size[0])
644
+ self.get_corner_and_lines()
645
+
646
+ # def clear_curve_widget(self):
@@ -0,0 +1,5 @@
1
+
2
+
3
+
4
+
5
+