batoolset 0.1.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (162) hide show
  1. batoolset/GUI/__init__.py +0 -0
  2. batoolset/GUI/list_gui.py +513 -0
  3. batoolset/GUI/multi_image_display.py +989 -0
  4. batoolset/GUI/open.py +325 -0
  5. batoolset/GUI/overlay_hints.py +45 -0
  6. batoolset/GUI/paint2.py +1345 -0
  7. batoolset/GUI/scrollablepaint.py +1152 -0
  8. batoolset/IJ_ROIs/__init__.py +0 -0
  9. batoolset/IJ_ROIs/tools.py +40 -0
  10. batoolset/PATH/__init__.py +0 -0
  11. batoolset/PATH/tools.py +79 -0
  12. batoolset/SQLite_tools/__init__.py +0 -0
  13. batoolset/SQLite_tools/tools.py +840 -0
  14. batoolset/__init__.py +0 -0
  15. batoolset/binary/__init__.py +0 -0
  16. batoolset/binary/tools.py +123 -0
  17. batoolset/binarytools/__init__.py +0 -0
  18. batoolset/binarytools/cell_center_detector.py +290 -0
  19. batoolset/clipboard_tools/__init__.py +0 -0
  20. batoolset/clipboard_tools/tools.py +7 -0
  21. batoolset/colors/__init__.py +0 -0
  22. batoolset/colors/colorgen.py +193 -0
  23. batoolset/colors/tools.py +22 -0
  24. batoolset/command_line/__init__.py +0 -0
  25. batoolset/command_line/tools.py +18 -0
  26. batoolset/dialogs/__init__.py +0 -0
  27. batoolset/dialogs/opensave.py +228 -0
  28. batoolset/dicts/__init__.py +0 -0
  29. batoolset/dicts/tools.py +299 -0
  30. batoolset/dims/__init__.py +0 -0
  31. batoolset/dims/tools.py +83 -0
  32. batoolset/draw/__init__.py +0 -0
  33. batoolset/draw/shapes/Position.py +183 -0
  34. batoolset/draw/shapes/__init__.py +0 -0
  35. batoolset/draw/shapes/automated_alignment_drawing_refactored.py +346 -0
  36. batoolset/draw/shapes/circle2d.py +99 -0
  37. batoolset/draw/shapes/compute_optimal_size_all_merged.py +317 -0
  38. batoolset/draw/shapes/ellipse2d.py +336 -0
  39. batoolset/draw/shapes/freehand2d.py +235 -0
  40. batoolset/draw/shapes/group.py +1830 -0
  41. batoolset/draw/shapes/image2d.py +2469 -0
  42. batoolset/draw/shapes/line2d.py +575 -0
  43. batoolset/draw/shapes/point2d.py +257 -0
  44. batoolset/draw/shapes/polygon2d.py +357 -0
  45. batoolset/draw/shapes/polyline2d.py +235 -0
  46. batoolset/draw/shapes/rect2d.py +388 -0
  47. batoolset/draw/shapes/rectangle2d.py +601 -0
  48. batoolset/draw/shapes/scalebar.py +304 -0
  49. batoolset/draw/shapes/serializablefont.py +126 -0
  50. batoolset/draw/shapes/serializableguiparams.py +10 -0
  51. batoolset/draw/shapes/square2d.py +103 -0
  52. batoolset/draw/shapes/textorientation.py +45 -0
  53. batoolset/draw/shapes/tools.py +467 -0
  54. batoolset/draw/shapes/transform2D.py +350 -0
  55. batoolset/draw/shapes/txt2d.py +550 -0
  56. batoolset/draw/widgets/__init__.py +0 -0
  57. batoolset/draw/widgets/col.py +343 -0
  58. batoolset/draw/widgets/image_group.py +248 -0
  59. batoolset/draw/widgets/image_organizer.py +96 -0
  60. batoolset/draw/widgets/paint.py +184 -0
  61. batoolset/draw/widgets/vectorial.py +257 -0
  62. batoolset/figure/__init__.py +0 -0
  63. batoolset/figure/alignment.py +814 -0
  64. batoolset/figure/column.py +1117 -0
  65. batoolset/figure/fig_tools.py +285 -0
  66. batoolset/figure/minimal_debugger_scale_etc.py +139 -0
  67. batoolset/figure/panel.py +697 -0
  68. batoolset/figure/row.py +852 -0
  69. batoolset/figure/user_selection.py +287 -0
  70. batoolset/files/__init__.py +0 -0
  71. batoolset/files/tools.py +1321 -0
  72. batoolset/images/__init__.py +0 -0
  73. batoolset/images/tools.py +81 -0
  74. batoolset/img.py +5216 -0
  75. batoolset/linux/__init__.py +0 -0
  76. batoolset/linux/tools.py +72 -0
  77. batoolset/lists/__init__.py +0 -0
  78. batoolset/lists/tools.py +436 -0
  79. batoolset/luts/__init__.py +0 -0
  80. batoolset/luts/lut_minimal_test.py +1207 -0
  81. batoolset/matplolib/__init__.py +0 -0
  82. batoolset/matplolib/tools.py +44 -0
  83. batoolset/np_tools/__init__.py +0 -0
  84. batoolset/np_tools/tools.py +252 -0
  85. batoolset/np_tools/trash.py +15 -0
  86. batoolset/pandas_tools/__init__.py +0 -0
  87. batoolset/pandas_tools/tools.py +880 -0
  88. batoolset/partials/__init__.py +0 -0
  89. batoolset/partials/tools.py +83 -0
  90. batoolset/plot_tools/__init__.py +0 -0
  91. batoolset/plot_tools/tools.py +70 -0
  92. batoolset/pyqt/__init__.py +0 -0
  93. batoolset/pyqt/tools.py +691 -0
  94. batoolset/re_tools/__init__.py +0 -0
  95. batoolset/re_tools/tools.py +35 -0
  96. batoolset/serialization/__init__.py +0 -0
  97. batoolset/serialization/tools.py +1192 -0
  98. batoolset/sets/__init__.py +0 -0
  99. batoolset/sets/tools.py +109 -0
  100. batoolset/settings/__init__.py +0 -0
  101. batoolset/settings/global_settings.py +134 -0
  102. batoolset/strings/__init__.py +0 -0
  103. batoolset/strings/tools.py +225 -0
  104. batoolset/ta/__init__.py +0 -0
  105. batoolset/ta/database/__init__.py +0 -0
  106. batoolset/ta/database/advanced_sql_plotter.py +1170 -0
  107. batoolset/ta/database/my_qt_table.py +79 -0
  108. batoolset/ta/database/preview_and_edit_sqlite_db.py +405 -0
  109. batoolset/ta/database/sql.py +2141 -0
  110. batoolset/ta/database/sql_column_name_dialog.py +122 -0
  111. batoolset/ta/measurements/TAmeasures.py +2226 -0
  112. batoolset/ta/measurements/__init__.py +0 -0
  113. batoolset/ta/measurements/measurements3D/__init__.py +0 -0
  114. batoolset/ta/measurements/measurements3D/get_point_on_surface_if_centroid_is_bad.py +175 -0
  115. batoolset/ta/measurements/measurements3D/height_map_to_projection.py +82 -0
  116. batoolset/ta/measurements/measurements3D/measures3D.py +208 -0
  117. batoolset/ta/measurements/measurements3D/triangulate.py +331 -0
  118. batoolset/ta/measurements/nematic.py +562 -0
  119. batoolset/ta/measurements/nematic_measurements.py +107 -0
  120. batoolset/ta/segmentation/__init__.py +0 -0
  121. batoolset/ta/segmentation/neo_wshed.py +314 -0
  122. batoolset/ta/selections/__init__.py +0 -0
  123. batoolset/ta/selections/selection.py +329 -0
  124. batoolset/ta/tracking/__init__.py +0 -0
  125. batoolset/ta/tracking/last_tracking_based_on_matching_or_on_translation_from_mermaid_warp.py +653 -0
  126. batoolset/ta/tracking/local_to_track_correspondance.py +138 -0
  127. batoolset/ta/tracking/rapid_detection_of_vertices.py +517 -0
  128. batoolset/ta/tracking/registration.py +108 -0
  129. batoolset/ta/tracking/swap_detector_and_fixer.py +296 -0
  130. batoolset/ta/tracking/track_correction.py +238 -0
  131. batoolset/ta/tracking/tracking_error_detector_and_fixer.py +3099 -0
  132. batoolset/ta/tracking/tracking_yet_another_approach_pyramidal_registration_n_neo_swapping_correction.py +725 -0
  133. batoolset/ta/utils/TA_tools.py +43 -0
  134. batoolset/ta/utils/__init__.py +0 -0
  135. batoolset/ta/utils/rps_tools.py +1783 -0
  136. batoolset/tests/__init__.py +0 -0
  137. batoolset/tests/rps_tools.py +51 -0
  138. batoolset/tests/tools.py +10 -0
  139. batoolset/tools/__init__.py +0 -0
  140. batoolset/tools/early_stopper_class.py +9 -0
  141. batoolset/tools/guided_data_recoverer.py +110 -0
  142. batoolset/tools/logger.py +100 -0
  143. batoolset/tools/mytimer.py +31 -0
  144. batoolset/tools/prompt_color.py +160 -0
  145. batoolset/tools/qthandler.py +118 -0
  146. batoolset/uitools/__init__.py +0 -0
  147. batoolset/uitools/blinker.py +56 -0
  148. batoolset/unsafe/__init__.py +0 -0
  149. batoolset/unsafe/tools.py +115 -0
  150. batoolset/utils/__init__.py +0 -0
  151. batoolset/utils/commontools.py +158 -0
  152. batoolset/utils/loadlist.py +728 -0
  153. batoolset/version.py +10 -0
  154. batoolset/xml/__init__.py +0 -0
  155. batoolset/xml/tools.py +65 -0
  156. batoolset/zip_tools/__init__.py +0 -0
  157. batoolset/zip_tools/tools.py +76 -0
  158. batoolset-0.1.0.dist-info/LICENSE +24 -0
  159. batoolset-0.1.0.dist-info/METADATA +45 -0
  160. batoolset-0.1.0.dist-info/RECORD +162 -0
  161. batoolset-0.1.0.dist-info/WHEEL +5 -0
  162. batoolset-0.1.0.dist-info/top_level.txt +1 -0
@@ -0,0 +1,1152 @@
1
+ # channels seem be fixed --> cool
2
+ # finalize whsed and corrections --> make sure they are channel dependent
3
+ # check which channels are being restored by the new wshed within the paint arena
4
+ from batoolset.settings.global_settings import set_UI # set the UI to qtpy
5
+ set_UI()
6
+ import os
7
+ # in set image add sliders for D and Z --> see how I can do that --> or do it directly in paint ????
8
+ import traceback
9
+ import matplotlib.pyplot as plt
10
+ import numpy as np
11
+ from qtpy import QtWidgets, QtCore, QtGui
12
+ from qtpy.QtCore import QSize, Qt
13
+ from qtpy.QtGui import QPalette, QKeySequence, QPainter
14
+ from qtpy.QtWidgets import QScrollArea, QVBoxLayout, QWidget, QSpinBox, QComboBox, QToolBar, QStatusBar, QLabel, \
15
+ QHBoxLayout, QAction, QSlider
16
+ import qtawesome as qta
17
+ from qtpy.QtCore import Qt, QTimer
18
+ from batoolset.draw.shapes.freehand2d import Freehand2D
19
+ from batoolset.draw.shapes.image2d import Image2D
20
+ from batoolset.draw.shapes.rect2d import Rect2D
21
+ from batoolset.img import Img, int24_to_RGB, has_metadata
22
+ from batoolset.GUI.paint2 import Createpaintwidget
23
+
24
+ # TODO --> could maybe add icons just below scroll if needed to add actions
25
+ # j'arrive pas à creer un truc dejà self embedded
26
+ # make it also handle other stuff
27
+
28
+ # --> nb replace the Createpaintwidget in multi_image_display.py by this --> better in fact
29
+ # shall I do full screen ???
30
+ # TODO handle channels too if needed
31
+ # could store mask and memory of drawing here too --> maybe on mouse release ???
32
+ # avec des ctrl+Z et des ctrl+R
33
+
34
+
35
+ # need zooms
36
+ #
37
+
38
+ class scrollable_paint(QWidget):
39
+
40
+ def __init__(self, custom_paint_panel=None):
41
+ super().__init__()
42
+ if custom_paint_panel is None:
43
+ self.paint = Createpaintwidget()
44
+ else:
45
+ self.paint = custom_paint_panel
46
+ layout = QVBoxLayout()
47
+
48
+ # delay dimensionality change update --> just to make sure it does not overwhelms the system upon slider change
49
+ # think about how to do that in a smart way -> maybe by changing the connect ???
50
+ # self.delayed_dimension_preview = QTimer()
51
+ # self.delayed_dimension_preview.setSingleShot(True)
52
+ # self.delayed_dimension_preview.timeout.connect(self.slider_dimension_value_changed)
53
+ self.dimension_sliders = []
54
+ self.is_width_for_alternating = True
55
+ # add the possibility to browse dimensions
56
+ self.dimensions_container = QVBoxLayout() # this will contain all the browsable dimensions of the image
57
+ # fake add sliders here
58
+ # self.dim_slider_with_label1 = self.create_dim_slider(dimension='d', max_dim=16)
59
+ # self.dimensions_container.addLayout(self.dim_slider_with_label1)
60
+ # self.dim_slider_with_label2 = self.create_dim_slider(dimension='c', max_dim=3)
61
+ # self.dimensions_container.addLayout(self.dim_slider_with_label2)
62
+ # self.dim_slider_with_label3 = self.create_dim_slider(dimension='t', max_dim=22)
63
+ # self.dimensions_container.addLayout(self.dim_slider_with_label3)
64
+ # each of the sliders will be assoc to a single dim --> TODO
65
+ # maybe remove the slider for channels ???
66
+ # same as the other with embed in scroll area
67
+ self.scrollArea = QScrollArea()
68
+ self.scrollArea.setBackgroundRole(QPalette.Dark)
69
+ self.scrollArea.setWidget(self.paint)
70
+ self.paint.scrollArea = self.scrollArea
71
+ layout.addLayout(self.dimensions_container)
72
+ layout.addWidget(self.scrollArea)
73
+ self.setLayout(layout)
74
+ status_bar = QStatusBar()
75
+ layout.addWidget(status_bar)
76
+ self.paint.statusBar = status_bar
77
+ self.add_shortcuts()
78
+ self.drawing_commands()
79
+
80
+ # this guy should handle the shortcuts it can and pass the rest to the other layer
81
+ def add_shortcuts(self):
82
+ # print('SHORTCUTS ADDED')
83
+
84
+ # if True:
85
+ # return
86
+ zoomPlus = QtWidgets.QShortcut("Ctrl+Shift+=", self)
87
+ zoomPlus.activated.connect(self.zoomIn)
88
+ zoomPlus.setContext(QtCore.Qt.ApplicationShortcut)
89
+
90
+
91
+
92
+ # that works and disconnects all
93
+ # zoomPlus.disconnect()
94
+
95
+
96
+
97
+ zoomPlus2 = QtWidgets.QShortcut("Ctrl++", self)
98
+ zoomPlus2.activated.connect(self.zoomIn)
99
+ zoomPlus2.setContext(QtCore.Qt.ApplicationShortcut)
100
+
101
+ zoomMinus = QtWidgets.QShortcut("Ctrl+Shift+-", self)
102
+ zoomMinus.activated.connect(self.zoomOut)
103
+ zoomMinus.setContext(QtCore.Qt.ApplicationShortcut)
104
+
105
+ zoomMinus2 = QtWidgets.QShortcut("Ctrl+-", self)
106
+ zoomMinus2.activated.connect(self.zoomOut)
107
+ zoomMinus2.setContext(QtCore.Qt.ApplicationShortcut)
108
+
109
+ ctrl0 = QtWidgets.QShortcut("Ctrl+0", self)
110
+ ctrl0.activated.connect(self.zoom_reset)
111
+ ctrl0.setContext(QtCore.Qt.ApplicationShortcut)
112
+
113
+ self.ctrlS = QtWidgets.QShortcut("Ctrl+S", self)
114
+ self.ctrlS.activated.connect(self.paint.save)
115
+ self.ctrlS.setContext(QtCore.Qt.ApplicationShortcut)
116
+
117
+
118
+ self.ctrlM = QtWidgets.QShortcut("Ctrl+M", self)
119
+ self.ctrlM.activated.connect(self.paint.ctrl_m_apply)
120
+ self.ctrlM.setContext(QtCore.Qt.ApplicationShortcut)
121
+
122
+ self.shrtM = QtWidgets.QShortcut("M", self)
123
+ self.shrtM.activated.connect(self.paint.m_apply)
124
+ self.shrtM.setContext(QtCore.Qt.ApplicationShortcut)
125
+
126
+ self.increase_contrastC = QtWidgets.QShortcut('C', self)
127
+ self.increase_contrastC.activated.connect(self.paint.increase_contrast)
128
+ self.increase_contrastC.setContext(QtCore.Qt.ApplicationShortcut)
129
+
130
+ # I can connect to progeny --> makes sense and really easy --> cool
131
+ self.enterShortcut = QtWidgets.QShortcut(QtGui.QKeySequence(QtCore.Qt.Key_Return), self)
132
+ self.enterShortcut.activated.connect(self.paint.apply)
133
+ self.enterShortcut.setContext(QtCore.Qt.ApplicationShortcut)
134
+
135
+ self.enterShortcut2 = QtWidgets.QShortcut(QtGui.QKeySequence(QtCore.Qt.Key_Enter), self)
136
+ self.enterShortcut2.activated.connect(self.paint.apply)
137
+ self.enterShortcut2.setContext(QtCore.Qt.ApplicationShortcut)
138
+
139
+ # en fait je peux aussi connecter des trucs au descendant --> pas bete et tres facile à faire!!!
140
+
141
+ # pkoi ça ne marche pas !!!
142
+ self.shiftEnterShortcut = QtWidgets.QShortcut("Shift+Enter", self)
143
+ self.shiftEnterShortcut.activated.connect(self.paint.shift_apply)
144
+ self.shiftEnterShortcut.setContext(QtCore.Qt.ApplicationShortcut)
145
+ #
146
+ self.shiftEnterShortcut2 = QtWidgets.QShortcut("Shift+Return", self)
147
+ self.shiftEnterShortcut2.activated.connect(self.paint.shift_apply)
148
+ self.shiftEnterShortcut2.setContext(QtCore.Qt.ApplicationShortcut)
149
+
150
+ self.ctrl_shift_S_grab_screen_shot = QtWidgets.QShortcut('Ctrl+Shift+S', self)
151
+ self.ctrl_shift_S_grab_screen_shot.activated.connect(self.paint.grab_screen_shot)
152
+ self.ctrl_shift_S_grab_screen_shot.setContext(QtCore.Qt.ApplicationShortcut)
153
+
154
+ self.supr = QtWidgets.QShortcut(QKeySequence(Qt.Key_Delete), self)
155
+ self.supr.activated.connect(self.paint.suppr_pressed)
156
+ self.supr.setContext(QtCore.Qt.ApplicationShortcut)
157
+
158
+
159
+
160
+ # peut etre faire un fullscreen shortcut --> can be useful
161
+
162
+ def enable_shortcuts(self):
163
+ self.disable_shortcuts()
164
+ self.ctrlS.activated.connect(self.paint.save)
165
+ self.ctrlM.activated.connect(self.paint.ctrl_m_apply)
166
+ self.shrtM.activated.connect(self.paint.m_apply)
167
+ self.enterShortcut.activated.connect(self.paint.apply)
168
+ self.enterShortcut2.activated.connect(self.paint.apply)
169
+ self.shiftEnterShortcut.activated.connect(self.paint.shift_apply)
170
+ self.shiftEnterShortcut2.activated.connect(self.paint.shift_apply)
171
+
172
+ def disable_shortcuts(self):
173
+ # TODO
174
+ try:
175
+ self.ctrlS.disconnect()
176
+ except:
177
+ pass
178
+ # TODO
179
+ try:
180
+ self.ctrlM.disconnect()
181
+ except:
182
+ pass
183
+ try:
184
+ self.shrtM.disconnect()
185
+ except:
186
+ pass
187
+ try:
188
+ self.enterShortcut.disconnect()
189
+ except:
190
+ pass
191
+ try:
192
+ self.enterShortcut2.disconnect()
193
+ except:
194
+ pass
195
+ try:
196
+ self.shiftEnterShortcut.disconnect()
197
+ except:
198
+ pass
199
+ try:
200
+ self.shiftEnterShortcut2.disconnect()
201
+ except:
202
+ pass
203
+
204
+ def enableMouseTracking(self):
205
+ self.paint.drawing_enabled = True
206
+
207
+ def disableMouseTracking(self):
208
+ self.paint.drawing_enabled = False
209
+
210
+
211
+ # def gather_indices_for_all_dimensions(self):
212
+ # loop through the content of an image ????
213
+
214
+
215
+
216
+ # ça marche --> ajouter fit to width ou fit to height
217
+ def fit_to_width_or_height(self):
218
+ if self.is_width_for_alternating:
219
+ self.fit_to_width()
220
+ else:
221
+ self.fit_to_height()
222
+ self.is_width_for_alternating = not self.is_width_for_alternating
223
+
224
+ # almost there but small bugs
225
+ def fit_to_width(self):
226
+ if self.paint.image is None:
227
+ return
228
+ # self.scrollArea = self.scroll_areas[nb]
229
+ width = self.scrollArea.width() - 2
230
+ width -= self.scrollArea.verticalScrollBar().sizeHint().width()
231
+ # height-=self.scrollArea.horizontalScrollBar().sizeHint().height()
232
+ width_im = self.paint.image.width()
233
+ scale = width / width_im
234
+ self.scaleImage(scale)
235
+
236
+ def fit_to_height(self, nb=0):
237
+ # paint = self.paints[nb]
238
+ if self.paint.image is None:
239
+ return
240
+ # scrollArea = self.scroll_areas[nb]
241
+ height = self.scrollArea.height() - 2
242
+ height -= self.scrollArea.horizontalScrollBar().sizeHint().height()
243
+ height_im = self.paint.image.height()
244
+ scale = height / height_im
245
+ self.scaleImage(scale)
246
+
247
+ def fit_to_window(self):
248
+ # compute best fit
249
+ # just get the size of the stuff and best fit it
250
+ # paint = self.paints[nb]
251
+ if self.paint.image is None:
252
+ return
253
+
254
+ # QScrollArea.ensureWidgetVisible(
255
+ # QScrollArea.ensureVisible
256
+ # QScrollArea.setWidgetResizable
257
+ # scrollArea = self.scroll_areas[nb]
258
+ width = self.scrollArea.width() - 2 # required to make sure bars not visible
259
+ height =self. scrollArea.height() - 2
260
+
261
+ # scale image that it fits in --> change scale
262
+
263
+ # width-=self.scrollArea.verticalScrollBar().sizeHint().width()
264
+ # height-=self.scrollArea.horizontalScrollBar().sizeHint().height()
265
+
266
+ height_im = self.paint.image.height()
267
+ width_im = self.paint.image.width()
268
+ scale = height / height_im
269
+ if width / width_im < scale:
270
+ scale = width / width_im
271
+ self.scaleImage(scale)
272
+
273
+
274
+
275
+
276
+ def zoomIn(self):
277
+ # 10% more each time
278
+ self.scaleImage(self.paint.scale + (self.paint.scale*10.0/100.0))# une hausse de 10% à chaque fois
279
+
280
+ def zoomOut(self):
281
+ # 10% less each time
282
+ self.scaleImage(self.paint.scale - (self.paint.scale*10.0/100.0))
283
+
284
+ def zoom_reset(self):
285
+ # resets zoom
286
+ self.scaleImage(1.0)
287
+
288
+ # pb this is redundant with the main GUI and not in sync --> can cause a lot of trouble --> dactivate for now
289
+ def full_screen(self):
290
+ if not self.isFullScreen():
291
+ self.fullscreen.setIcon(qta.icon('mdi.fullscreen-exit'))
292
+ self.fullscreen.setToolTip('Exit full screen')
293
+ self.showFullScreen()
294
+ # self.setWindowFlags(
295
+ # QtCore.Qt.Window |
296
+ # QtCore.Qt.CustomizeWindowHint |
297
+ # # QtCore.Qt.WindowTitleHint |
298
+ # # QtCore.Qt.WindowCloseButtonHint |
299
+ # QtCore.Qt.WindowStaysOnTopHint
300
+ # )
301
+ else:
302
+ # settings = QSettings()
303
+ # self.Stack.restoreGeometry(settings.value("geometry")) #.toByteArray()
304
+ self.fullscreen.setIcon(qta.icon('mdi.fullscreen'))
305
+ self.fullscreen.setToolTip('Enter full screen')
306
+ self.setWindowFlags(QtCore.Qt.Widget)
307
+ # # self.Stack.setWindowFlags(self.flags)
308
+ # self.grid.addWidget(self.Stack, 0,
309
+ # 0) # pas trop mal mais j'arrive pas à le remettre dans le truc principal
310
+ # # dirty hack to make it repaint properly --> obviously not all lines below are required but some are --> need test, the last line is key though
311
+ # self.grid.update()
312
+ # self.Stack.update()
313
+ # self.Stack.show()
314
+ # self.centralWidget().setLayout(self.grid)
315
+ # self.centralWidget().update()
316
+ # self.update()
317
+ self.show()
318
+ self.repaint()
319
+ # self.Stack.update()
320
+ # self.Stack.repaint()
321
+ # self.centralWidget().repaint()
322
+
323
+ def scaleImage(self, scale):
324
+ self.paint.set_scale(scale)
325
+ if self.paint.image is not None:
326
+ self.paint.resize(self.paint.scale * self.paint.image.size())
327
+ else:
328
+ self.paint.resize(QSize(0, 0))
329
+ self.paint.update()
330
+
331
+ # can maybe add pen stuff here --> simpler and easier
332
+ # need zoom buttons here too
333
+ '''
334
+ buttons/icons to add at some point
335
+
336
+
337
+ "Cell smaller than this value will be destroyed"
338
+ "small_cell_remover"
339
+
340
+
341
+ "/Icons/refresh.png"
342
+ "run 2 seeds watershed (click twice in a poorly segmented cell to have a the bond be created using the watershed algorithm)"
343
+
344
+ "/Icons/Knob Snapback.png"
345
+ "Undo"
346
+
347
+ "/Icons/Knob Valid Blue.png"
348
+ "remove small cells and apply correction"
349
+
350
+ "/Icons/Knob Valid Green.png"
351
+ "apply correction"
352
+
353
+ "/Icons/channels.png"
354
+ "Channel Selection"
355
+ "Channel to use for Watershed, polarity, recentering,...")
356
+
357
+ "/Icons/onebit_11.png"
358
+ "Save"
359
+
360
+
361
+ "/Icons/eye.png"
362
+ "View below the mask (lasts 2s)"
363
+
364
+
365
+ "/Icons/zoom in.png"
366
+ "Zoom +"
367
+
368
+ "/Icons/zoom out.png"
369
+ "Zoom -"
370
+
371
+ "/Icons/1in1.png"
372
+ "1:1 aspect ratio"
373
+
374
+ "/Icons/fit_2_screen.gif"
375
+ "Fit to panel"
376
+
377
+
378
+ "/Icons/double_diagonal_arrow.gif"
379
+ "Alternate between best fit in height or in width"
380
+
381
+
382
+ "/Icons/Import Picture Document.png"
383
+ "Send Current View To The System Clipboard"
384
+
385
+ "/Icons/pipet_small.png"
386
+ "Color pipet"
387
+
388
+ "Mask col"
389
+ "mask color"
390
+
391
+ "Correct Drift"
392
+
393
+ '''
394
+
395
+ # add shortcut for show hide mask and maybe also full screen --> not a good idea
396
+
397
+ def drawing_commands(self):
398
+ self.penSize = QSpinBox(objectName='penSize')
399
+ self.penSize.setToolTip('Change this value to change pen size')
400
+ self.penSize.setSingleStep(1)
401
+ self.penSize.setRange(1, 256)
402
+ self.penSize.setValue(3)
403
+ self.penSize.valueChanged.connect(self.penSizechange)
404
+
405
+ self.channels = QComboBox(objectName='channels')
406
+ self.channels.setToolTip('Select the channel of interest')
407
+ self.channels.addItem("merge")
408
+ # self.channels.addItem("0")
409
+ # self.channels.addItems(["1", "2", "3"])
410
+ self.channels.currentIndexChanged.connect(self.channelChange)
411
+
412
+
413
+ hlayout_of_toolbars = QHBoxLayout()
414
+ hlayout_of_toolbars.setAlignment(Qt.AlignLeft)
415
+ self.tb1 = QToolBar()
416
+ self.tb2 = QToolBar()
417
+ self.tb3 = QToolBar()
418
+
419
+
420
+ pencil_action = QAction(qta.icon('ei.pencil'), 'Pen Size', self)
421
+ pencil_action.setEnabled(False)
422
+ self.tb2.addAction(pencil_action)
423
+ # tb.addAction("sq...")
424
+ self.tb2.addWidget(self.penSize)
425
+
426
+ # toolButton = QToolButton()
427
+ # toolButton.setText("Draw")
428
+ # toolButton.setIcon(self.style().standardIcon(QStyle.SP_DriveFDIcon))
429
+ # tb.addWidget(toolButton)
430
+
431
+ # fa5.save
432
+ save_action = QAction(qta.icon('fa5.save'), 'Save mask', self)
433
+ save_action.triggered.connect(self.paint.save)
434
+ self.tb2.addAction(save_action)
435
+
436
+
437
+ # toolButton2 = QToolButton()
438
+ # toolButton2.setText("Draw")
439
+ # toolButton2.setIcon(self.style().standardIcon(QStyle.SP_DialogApplyButton))
440
+ # tb.addWidget(toolButton2)
441
+
442
+
443
+ show_hide_mask =QAction(qta.icon('fa.bullseye'), 'Show/hide mask (same as pressing "M")', self)
444
+ show_hide_mask.triggered.connect(self.paint.m_apply)
445
+ self.tb2.addAction(show_hide_mask)
446
+
447
+ apply_drawing = QAction(qta.icon('fa.check'), 'Apply drawing (same as pressing the "Enter" key)', self)
448
+ apply_drawing.triggered.connect(self.paint.apply)
449
+ self.tb2.addAction(apply_drawing)
450
+
451
+ # toolButton3 = QToolButton()
452
+ # toolButton3.setText("Draw")
453
+ # toolButton3.setIcon(self.style().standardIcon(QStyle.SP_DialogCancelButton))
454
+ # tb.addWidget(toolButton3)
455
+
456
+ # toolButton4 = QToolButton()
457
+ # toolButton4.setText("Draw")
458
+ # toolButton4.setIcon(self.style().standardIcon(QStyle.SP_DialogCloseButton))
459
+ # tb.addWidget(toolButton4)
460
+
461
+ # toolButton5 = QToolButton()
462
+ # toolButton5.setText("Draw")
463
+ # toolButton5.setIcon(self.style().standardIcon(QStyle.SP_TrashIcon))
464
+ # tb.addWidget(toolButton5)
465
+
466
+ # toolButton6 = QToolButton()
467
+ # toolButton6.setText("Draw")
468
+ # toolButton6.setIcon(self.style().standardIcon(QStyle.SP_ArrowBack))
469
+ # tb.addWidget(toolButton6)
470
+
471
+ # toolButton7 = QToolButton()
472
+ # toolButton7.setText("Draw")
473
+ # toolButton7.setIcon(self.style().standardIcon(QStyle.SP_BrowserReload))
474
+ # tb.addWidget(toolButton7)
475
+
476
+ self.small_cell_size = QSpinBox()
477
+ self.small_cell_size.setToolTip('Select the minimal pixel area for a cell to be considered as a cell.\nAny cell having an area less than this value will be removed.')
478
+ self.small_cell_size.setSingleStep(1)
479
+ self.small_cell_size.setRange(1, 1000000)
480
+ self.small_cell_size.setValue(10)
481
+ self.small_cell_size.valueChanged.connect(self.small_cell_size_changed)
482
+
483
+ self.tb2.addWidget(self.small_cell_size)
484
+ apply_rm_small_cells = QAction(qta.icon('mdi.check-underline'), 'Apply drawing and remove small cells (same as pressing "Shift+Enter")', self)
485
+ apply_rm_small_cells.triggered.connect(self.paint.shift_apply)# self.paint.shift_apply
486
+ self.tb2.addAction(apply_rm_small_cells)
487
+
488
+
489
+
490
+
491
+
492
+ # marche pas --> comment faire pr que ça marche...
493
+ local_reshed = QAction(qta.icon('mdi.reload'), 'Locally seeded watershed (same as pressing "Ctrl/Cmd + M")', self)
494
+ local_reshed.triggered.connect(self.paint.ctrl_m_apply)# self.paint.shift_apply
495
+ self.tb2.addAction(local_reshed)
496
+ # hgjhghj
497
+
498
+ # toolButton8 = QToolButton()
499
+ # toolButton8.setText("Zoom+")
500
+ # toolButton8.setIcon(qta.icon('ei.zoom-in')) # mdi.magnify-plus-outline --> marche aussi
501
+ # tb.addWidget(toolButton8)
502
+
503
+ # toolButton9 = QToolButton()
504
+ # toolButton9.setText("Zoom-")
505
+ # toolButton9.setIcon(qta.icon('ei.zoom-out'))
506
+ # tb.addWidget(toolButton9)
507
+
508
+ zoom_plus = QAction(qta.icon('ei.zoom-in'), 'Zoom+', self)
509
+ zoom_plus.triggered.connect(self.zoomIn)
510
+ self.tb1.addAction(zoom_plus)
511
+
512
+ zoom_minus = QAction(qta.icon('ei.zoom-out'), 'Zoom-', self)
513
+ zoom_minus.triggered.connect(self.zoomOut)
514
+ self.tb1.addAction(zoom_minus)
515
+
516
+
517
+ zoom_width_or_height = QAction(qta.icon('mdi.fit-to-page-outline'), 'Alternates between best fit in width and height', self)
518
+ zoom_width_or_height.triggered.connect(self.fit_to_width_or_height)
519
+ self.tb1.addAction(zoom_width_or_height)
520
+
521
+ zoom_0 = QAction(qta.icon('ei.resize-full'), 'Reset zoom', self)
522
+ zoom_0.triggered.connect(self.zoom_reset)
523
+ self.tb1.addAction(zoom_0)
524
+
525
+ # redundant with TA full screen and not in sync --> disable for now
526
+ # self.fullscreen = QtWidgets.QAction(qta.icon('mdi.fullscreen'), 'Full screen', self)
527
+ # self.fullscreen.setToolTip('Enter full screen')
528
+ # self.fullscreen.triggered.connect(self.full_screen)
529
+ # self.tb1.addAction(self.fullscreen)
530
+
531
+
532
+
533
+
534
+ # exit_fullscreen = QtWidgets.QAction(qta.icon('mdi.fullscreen'), 'Full screen', self)
535
+ # exit_fullscreen.triggered.connect(self.showFullScreen)
536
+ # self.tb1.addAction(fullscreen)
537
+
538
+
539
+
540
+ self.channel_label = QLabel('Channels:')
541
+ self.channel_label.setToolTip('Select the channel of interest')
542
+ self.tb3.addWidget(self.channel_label)
543
+ self.tb3.addWidget(self.channels)
544
+
545
+ # mdi.fullscreen
546
+ # mdi.fullscreen-exit
547
+ # ei.fullscreen --> a bit less good I find
548
+ # fa.bullseye
549
+
550
+ # could have show and hide mask here --> see how I can do that --> but do not delete it in fact
551
+
552
+ # self.layout().addWidget(self.tb1)
553
+ hlayout_of_toolbars.addWidget(self.tb2)
554
+
555
+
556
+ # self.tb2.addAction('toto')
557
+ # self.tb2.addAction('ttutu')
558
+ # self.tb2.addAction('tata')
559
+ hlayout_of_toolbars.addWidget(self.tb3)
560
+
561
+
562
+ # one for the zooms
563
+ # one for drawing and apply different things
564
+ # TODO do several toolbars to deactivate different levels of stuff
565
+ # and only allow save in the appropriate stuff
566
+
567
+ # self.tb3.addAction('toto')
568
+ # self.tb3.addAction('ttutu')
569
+ # self.tb3.addAction('tata')
570
+ hlayout_of_toolbars.addWidget(self.tb1)
571
+
572
+ self.layout().addLayout(hlayout_of_toolbars)
573
+
574
+ def get_selected_channel(self):
575
+ idx = self.channels.currentIndex()
576
+ if idx == 0:
577
+ return None
578
+ else:
579
+ return idx-1
580
+
581
+ # TODO also implement channel change directly within the display tool
582
+ # if merge is applied --> apply on average of all channels --> maybe not so smart an idea but ok to start with and better than what I do in TA
583
+ def channelChange(self, i):
584
+ # update displayed image depending on channel
585
+ # dqqsdqsdqsd
586
+ # pass
587
+ # try change channel if
588
+
589
+
590
+ # tODO --> need at least to reactivate a bit that
591
+ # pass
592
+ # print('in channel change') # needs a fix
593
+ meta = None
594
+ try:
595
+ meta = self.paint.raw_image.metadata
596
+ except:
597
+ pass
598
+ self.paint.set_display(self.get_image_to_display_including_all_dims(), metadata=meta)
599
+ self.paint.channelChange(i, skip_update_display=True)
600
+
601
+ # print('in channel change !!!')
602
+ # if self.img is not None:
603
+ # # print('in', self.img.metadata)
604
+ # if self.Stack.currentIndex() == 0:
605
+ # # need copy the image --> implement that
606
+ # # print(self.img[..., i].copy())
607
+ # # print(self.img[..., i])
608
+ # if i == 0:
609
+ # self.paint.setImage(self.img)
610
+ # # print('original', self.img.metadata)
611
+ # else:
612
+ # # print('modified0', self.img.metadata)
613
+ # channel_img = self.img.imCopy(c=i - 1) # it's here that it is affected
614
+ # # print('modified1', self.img.metadata)
615
+ # # print('modified2', channel_img.metadata)
616
+ # self.paint.setImage(channel_img)
617
+ # self.paint.update()
618
+ # else:
619
+ # # logger.error("Not implemented yet TODO add support for channels in 3D viewer")
620
+ # # sdqdqsdsqdqsd
621
+ # self.loadVolume()
622
+ # or reimplement that for multi channels !!!
623
+
624
+
625
+
626
+ # TODO maybe handle pen size change directly within the display --> can be useful by the way
627
+ def small_cell_size_changed(self):
628
+ self.paint.minimal_cell_size = self.small_cell_size.value()
629
+
630
+ # TODO maybe handle pen size change directly within the display --> can be useful by the way
631
+ def penSizechange(self):
632
+ self.paint.brushSize = self.penSize.value()
633
+ # self.update() # too slow if I update --> avoid
634
+ # self.l1.setFont(QFont("Arial", size))
635
+
636
+ def set_image(self, img):
637
+ # probably I need store raw image to avoid issues --> TODO ???
638
+ self.paint.set_image(img)# bug seems to be here
639
+
640
+ img = self.paint.raw_image
641
+
642
+ self.update_image_dimensions()
643
+
644
+ # need also update the dimensions if any
645
+
646
+ # print(type(img))
647
+
648
+ # else I need also reset channels
649
+
650
+ # if img is not None:
651
+ # if img.has_c():
652
+ self._update_channels(img=img)
653
+ # print('out')
654
+ # channels = self.paint.get_nb_channels()
655
+ # self._update_channels(channels)
656
+ # make it update also the channels
657
+ def _delete_layout_content(self, layout):
658
+ for i in reversed(range(layout.count())):
659
+ layout.itemAt(i).widget().setParent(None)
660
+
661
+
662
+
663
+ # centralized version of the thing
664
+ def get_image_to_display_including_all_dims(self):
665
+ # print('in get_image_to_display_including_all_dims')
666
+ # returns the image to be displayed --> takes into account all the dimensions at once
667
+
668
+ #
669
+ # if self.raw_image is not None:
670
+ # if i == 0:
671
+ # self.set_display(self.raw_image)
672
+ # self.channel = None
673
+ # # print('original', self.img.metadata)
674
+ # else:
675
+ # # print('modified0', self.img.metadata)
676
+ # # I need a hack when the image is single channel yet I need several masks for it !!!
677
+ # if self.multichannel_mode and i - 1 >= self.raw_image.shape[-1]:
678
+ # channel_img = self.raw_image.imCopy(c=0) # if out of bonds load the first channel
679
+ # else:
680
+ # channel_img = self.raw_image.imCopy(c=i - 1) # it's here that it is affected
681
+ # self.channel = i - 1
682
+ # # print('modified1', self.img.metadata)
683
+ # # print('modified2', channel_img.metadata)
684
+ # self.set_display(
685
+ # channel_img) # maybe do a set display instead rather --> easier to handle --> does a subest of the other
686
+ image_to_display = None
687
+ try:
688
+ # need change just the displayed image
689
+ if has_metadata(self.paint.raw_image) and self.paint.raw_image.metadata['dimensions']:
690
+ # change the respective dim
691
+ # need all the spinner values to be recovered in fact
692
+ # and send the stuff
693
+ # print('dimension exists', self.objectName(),'--> changing it')
694
+
695
+ # need gather all the dimensions --> TODO
696
+ dimensions = self.paint.raw_image.metadata['dimensions']
697
+ position_h = dimensions.index('h')
698
+ image_to_display = self.paint.raw_image
699
+ if position_h != 0:
700
+ # loop for all the dimensions before
701
+ # print('changing stuff')
702
+ for pos_dim in range(0, position_h):
703
+ dim = dimensions[pos_dim]
704
+ value_to_set = self.get_dim_value_by_name(dim)
705
+ if value_to_set == None:
706
+ continue
707
+ else:
708
+ image_to_display = image_to_display[value_to_set]
709
+ # if not dimensions[pos_dim]==self.sender().objectName():
710
+ # image_to_display = image_to_display[0]
711
+ # else:
712
+ # image_to_display = image_to_display[self.sender().value()]
713
+ # self.paint.set_display(image_to_display)
714
+ channel_to_display = self.get_selected_channel()
715
+
716
+ # if force dimensions --> I need a hack even if
717
+ # hack for GT image editor --> where nb of channels are forced and do not necessarily match the channels of the image --> is that smart to put that here ???
718
+ if channel_to_display is not None and 'c' in dimensions:
719
+ if self.paint.multichannel_mode and channel_to_display >= self.paint.raw_image.shape[-1]:
720
+ image_to_display = image_to_display[..., 0]
721
+ else:
722
+ image_to_display=image_to_display[...,channel_to_display]
723
+ # print(image_to_display.shape)
724
+ except:
725
+ traceback.print_exc()
726
+ return image_to_display
727
+
728
+ def update_image_dimensions(self):
729
+ self.dimension_sliders = []
730
+
731
+ for i in reversed(range(self.dimensions_container.count())):
732
+ # print(i)
733
+ # print(self.dimensions_container.itemAt(i))
734
+ # self.dimensions_container.itemAt(i).widget().setParent(None)
735
+ self._delete_layout_content(self.dimensions_container.itemAt(i))
736
+
737
+ if self.paint.raw_image is None:
738
+ return
739
+
740
+ # empty the content of the slider and refill it
741
+ try:
742
+ treat_channels_as_a_browsable_dimension = False
743
+ if has_metadata(self.paint.raw_image):
744
+ dimensions = self.paint.raw_image.get_dimensions_as_string()
745
+
746
+ # if not self.paint.raw_image.has_c():
747
+ # nb_of_sliders = len(
748
+ # self.paint.raw_image.shape) - 2 # or -3 it depends whether I wanna show all the channels at once or not ???
749
+ # else:
750
+ # nb_of_sliders = len(
751
+ # self.paint.raw_image.shape) - 2 # or -3 it depends whether I wanna show all the channels at once or not ???
752
+
753
+ # print(nb_of_sliders)
754
+
755
+ # create an image with plenty of sliders --> TODO
756
+ # make the handling of the image to be displayed directly by the code !!!
757
+
758
+ # then I need couple each slider to a dimension
759
+
760
+ # dimensions that must have a slider
761
+ # --> all dimensions but hw and maybe c must have a slider --> TODO
762
+ for dim in dimensions:
763
+ if dim == 'h' or dim == 'y' or dim == 'w' or dim == 'x' or (
764
+ not treat_channels_as_a_browsable_dimension and dim == 'c'):
765
+ # we skip dimensions
766
+ continue
767
+ # print(dim, 'must have an assoicated slider')
768
+
769
+ # print(self.paint.raw_image.shape, ' toto ', )
770
+ self.dimensions_container.addLayout(self.create_dim_slider(dimension=dim, max_dim=self.paint.raw_image.shape[dimensions.index(dim)]))
771
+ except:
772
+ traceback.print_exc()
773
+
774
+ def set_mask(self, mask):
775
+ self.paint.set_mask(mask)
776
+
777
+ def _update_channels(self, img):
778
+ selection = self.channels.currentIndex()
779
+ self.channels.disconnect()
780
+ self.channels.clear()
781
+ comboData = ['merge']
782
+ if img is not None:
783
+ try:
784
+ if img.has_c():
785
+ for i in range(img.get_dimension('c')):
786
+ comboData.append(str(i))
787
+ except:
788
+ # assume image has no channel and return None
789
+ # or assume last stuff is channel if image has more than 2
790
+ pass
791
+ # logger.debug('channels found ' + str(comboData))
792
+ self.channels.addItems(comboData)
793
+ # index = self.channels.findData(selection)
794
+
795
+ self.channels.currentIndexChanged.connect(self.channelChange)
796
+ # print("data", index)
797
+ if selection != -1 and selection < self.channels.count():
798
+ self.channels.setCurrentIndex(selection)
799
+ # self.channelChange(selection)
800
+ else:
801
+ self.channels.setCurrentIndex(0)
802
+ # self.channelChange(0)
803
+
804
+
805
+ def freeze(self, bool, level=1):
806
+
807
+ self.tb1.setEnabled(True)
808
+ self.tb2.setEnabled(True)
809
+ self.tb3.setEnabled(True)
810
+
811
+ if level == 1:
812
+ self.tb2.setEnabled(not bool)
813
+ elif level == 2:
814
+ self.tb2.setEnabled(not bool)
815
+ self.tb3.setEnabled(not bool)
816
+
817
+ if bool:
818
+ self.disable_shortcuts()
819
+ else:
820
+ self.enable_shortcuts()
821
+ # remove draw mode maybe and freeze shortcuts
822
+
823
+ def create_dim_slider(self, dimension=None, max_dim=1):
824
+ dim_slider_with_label1 = QHBoxLayout()
825
+ label_slider1 = QLabel()
826
+ if dimension is not None:
827
+ label_slider1.setText(dimension)
828
+ fake_dim_slider = QSlider(Qt.Horizontal)
829
+ fake_dim_slider.setMinimum(0)
830
+ fake_dim_slider.setMaximum(max_dim-1)
831
+ dim_slider_with_label1.addWidget(label_slider1)
832
+ dim_slider_with_label1.addWidget(fake_dim_slider)
833
+ # dim_slider_with_label1
834
+ # add a partial?
835
+ fake_dim_slider.valueChanged.connect(self.slider_dimension_value_changed)
836
+ # fake_dim_slider.valueChanged.connect(lambda x: self.delayed_dimension_preview.start(600))
837
+ fake_dim_slider.setObjectName(dimension)
838
+ self.dimension_sliders.append(fake_dim_slider)
839
+ return dim_slider_with_label1
840
+
841
+ def get_dim_value_by_name(self, label):
842
+ for slider in self.dimension_sliders:
843
+ if slider.objectName() == label:
844
+ return slider.value()
845
+ return None
846
+
847
+ # def get_dims_value_by_name(self, label):
848
+ # for slider in self.dimension_sliders:
849
+ # if slider.objectName() == label:
850
+ # return slider.value()
851
+ # return None
852
+
853
+ # p
854
+ def slider_dimension_value_changed(self):
855
+ # TODO --> do delay only if necessary
856
+ # self.delayed_dimension_preview.stop()
857
+ # self.delayed_dimension_preview.start(600)
858
+
859
+ # self.delayed_dimension_preview.timeout.connect
860
+
861
+ # if self.delayed_dimension_preview.dis
862
+
863
+ # TODO only allow this when the dimension changing is over
864
+ # if the dimension exists --> print it
865
+ # print(self.sender(), self.sender().objectName(), self.sender().value())
866
+ # print(self.sender(), self.sender().objectName())
867
+ # print(sender)
868
+ #
869
+ # try:
870
+ # # need change just the displayed image
871
+ # if self.paint.raw_image.metadata['dimensions']:
872
+ # # change the respective dim
873
+ # # need all the spinner values to be recovered in fact
874
+ # # and send the stuff
875
+ # # print('dimension exists', self.objectName(),'--> changing it')
876
+ #
877
+ # # need gather all the dimensions --> TODO
878
+ # dimensions = self.paint.raw_image.metadata['dimensions']
879
+ # position_h = dimensions.index('h')
880
+ # image_to_display = self.paint.raw_image
881
+ # if position_h!=0:
882
+ # # loop for all the dimensions before
883
+ # # print('changing stuff')
884
+ # for pos_dim in range(0,position_h):
885
+ # dim = dimensions[pos_dim]
886
+ # value_to_set = self.get_dim_value_by_name(dim)
887
+ # if value_to_set == None:
888
+ # continue
889
+ # else:
890
+ # image_to_display = image_to_display[value_to_set]
891
+ # # if not dimensions[pos_dim]==self.sender().objectName():
892
+ # # image_to_display = image_to_display[0]
893
+ # # else:
894
+ # # image_to_display = image_to_display[self.sender().value()]
895
+ # self.paint.set_display(image_to_display)
896
+ # except:
897
+ # traceback.print_exc()
898
+
899
+ try:
900
+ meta = None
901
+ try:
902
+ meta = self.paint.raw_image.metadata
903
+ except:
904
+ pass
905
+ # metadata is required to get the luts properly
906
+ self.paint.set_display(self.get_image_to_display_including_all_dims(), metadata=meta)
907
+ except:
908
+ traceback.print_exc()
909
+
910
+ # pass
911
+
912
+ # then have a single code to handle dynamically all the dimension changes !!! --> TODO
913
+
914
+
915
+ # pas mal faut juste voir ce que je peux faire
916
+ # peut etre permetre de mettre des custom panels
917
+
918
+ if __name__ == '__main__':
919
+ import sys
920
+ from qtpy.QtWidgets import QApplication
921
+
922
+
923
+ # hand drawing panel
924
+ if False:
925
+
926
+ # TODO add a main method so it can be called directly
927
+ # maybe just show a canvas and give it interesting props --> TODO --> really need fix that too!!!
928
+
929
+
930
+ # should probably have his own scroll bar embedded somewhere
931
+
932
+ app = QApplication(sys.argv)
933
+
934
+
935
+ # quite easy todo in fact
936
+
937
+ # no clue why it always works just once
938
+
939
+
940
+ # maybe make a scrollable TA paint that will handle and behave like that
941
+ # maybe handle also stacks at some point ---> see how
942
+ # --> almost all is ok now
943
+ class overriding_apply(Createpaintwidget):
944
+ # all seems ok now and functions as in TA
945
+ # just do the shift enter to get rid of small cells
946
+
947
+ # avec ça ça marche 100% à la TA ... --> cool --> maybe make it a TA drawing pad
948
+ def apply(self):
949
+ self.apply_drawing(minimal_cell_size=0)
950
+
951
+ def shift_apply(self):
952
+ # MEGA TODO IMPLEMENT SIZE within this stuff!!!
953
+ self.apply_drawing(minimal_cell_size=10)
954
+
955
+ def ctrl_m_apply(self):
956
+ self.manually_reseeded_wshed()
957
+
958
+ def save(self):
959
+ self.save_mask()
960
+
961
+ w = scrollable_paint(
962
+ custom_paint_panel=overriding_apply()) # ça marche --> permet de mettre des paint panels avec des proprietes particulieres --> assez facile en fait
963
+ # w.set_image('/E/Sample_images/sample_images_PA/mini (copie)/focused_Series012.png')
964
+ # w.set_mask('/E/Sample_images/sample_images_PA/mini (copie)/focused_Series012/handCorrection.png')
965
+ # w.set_image('/E/Sample_images/sample_images_PA/test_complete_wing_raphael/Optimized_projection_018.png')
966
+ # w.set_mask('/E/Sample_images/sample_images_PA/test_complete_wing_raphael/neo_mask.tif')
967
+
968
+ w.set_image('/D/VirtualBox/book_chapter_image_segmentation_final_2021/new_figs/dataset_1/minimal_demo_sample_simplified_bckup_before_messing_with_two_seg_errors/1.tif')
969
+ w.set_mask('/D/VirtualBox/book_chapter_image_segmentation_final_2021/new_figs/dataset_1/minimal_demo_sample_simplified_bckup_before_messing_with_two_seg_errors/1/handCorrection.tif')
970
+
971
+
972
+ # ça marche mais tt finalizer
973
+ # that seems to work
974
+
975
+ # w.freeze(True)
976
+ # w.freeze(False)
977
+ # w.freeze(True)
978
+
979
+ # all is so easy to do this way
980
+
981
+ # ça marche --> tres facile a tester
982
+ # --> how can I do a zoom
983
+ # ask whether self scroll or not --> if scrollable
984
+
985
+ # mask = w.get_mask()
986
+ #
987
+ # plt.imshow(mask)
988
+ # plt.show()
989
+
990
+ w.show()
991
+ sys.exit(app.exec_())
992
+
993
+ # vectorial panel for drawing ROIs --> that works --> keep this code cause very useful and many bug fix
994
+ # TODO try convert any ROIs to something like a contour using the pavlidis algo --> put this in rps tools
995
+
996
+ if True:
997
+ # TODO add a main method so it can be called directly
998
+ # maybe just show a canvas and give it interesting props --> TODO --> really need fix that too!!!
999
+
1000
+ # should probably have his own scroll bar embedded somewhere
1001
+
1002
+ app = QApplication(sys.argv)
1003
+
1004
+
1005
+ # quite easy todo in fact
1006
+
1007
+ # no clue why it always works just once
1008
+
1009
+ # maybe make a scrollable TA paint that will handle and behave like that
1010
+ # maybe handle also stacks at some point ---> see how
1011
+ # --> almost all is ok now
1012
+ class overriding_apply(Createpaintwidget):
1013
+ # all seems ok now and functions as in TA
1014
+ # just do the shift enter to get rid of small cells
1015
+ def m_apply(self):
1016
+ self.vdp.active = not self.vdp.active
1017
+ self.update()
1018
+
1019
+ # avec ça ça marche 100% à la TA ... --> cool --> maybe make it a TA drawing pad
1020
+ def apply(self):
1021
+ # self.apply_drawing(minimal_cell_size=0)
1022
+ pass
1023
+
1024
+ def shift_apply(self):
1025
+ # MEGA TODO IMPLEMENT SIZE within this stuff!!!
1026
+ # self.apply_drawing(minimal_cell_size=10)
1027
+ pass
1028
+
1029
+ def ctrl_m_apply(self):
1030
+ # print('seed')
1031
+ # self.manually_reseeded_wshed()
1032
+ pass
1033
+
1034
+ def save(self):
1035
+ # self.save_mask()
1036
+ print('saving ROIs')
1037
+ print(self.vdp.shapes)
1038
+ # create an image the save size as the displayed one and open it
1039
+ if self.raw_image is None:
1040
+ return
1041
+ if len(self.raw_image.shape)==2:
1042
+ black_image = np.zeros_like(self.raw_image, dtype=np.uint64)
1043
+ else:
1044
+ black_image = np.zeros(shape=(*self.raw_image[:-1],), dtype=np.uint64)
1045
+ # plt.imshow(black_image)
1046
+ # plt.show()
1047
+ # make it fill all the ROIs inside that
1048
+ im2d = Image2D(black_image)
1049
+
1050
+ for iii,shape in enumerate(self.vdp.shapes):
1051
+ # ideally need clone it and make it the enumerate color +1
1052
+
1053
+ shape.fill_color = iii+1
1054
+ shape.color = None
1055
+ # print(shape.fill_color)
1056
+ # print(type(shape), shape.fill_color)
1057
+ im2d.annotation.append(shape)
1058
+
1059
+
1060
+
1061
+ # im2d.annotation.extend(self.vdp.shapes)
1062
+
1063
+ # need clone the shape
1064
+
1065
+ # I need remove antialiasing
1066
+ im = im2d.save(None,quality=QPainter.NonCosmeticDefaultPen)
1067
+ im = im2d.convert_qimage_to_numpy(im)
1068
+
1069
+ # restore colors
1070
+ for shape in self.vdp.shapes:
1071
+ shape.fill_color = None
1072
+ shape.color = 0xFFFFFF
1073
+
1074
+ # faudrait tester en grandeur reelle pr voir si ça marche --> à faire !!!
1075
+ if True:
1076
+ # TODO just save the raw file in one channel not in many --> check the output by the way
1077
+
1078
+ # from skimage.measure import label
1079
+ # lab = label(im, connectivity=2, background=0)
1080
+ # im=lab
1081
+
1082
+ # I need remove antialiasing
1083
+ Img(im.astype(np.float64), dimensions='hwc').save('/E/Sample_images/sample_image_neurons_laurence_had/data_test/test_raw.tif')
1084
+
1085
+ plt.imshow(im)
1086
+ plt.show()
1087
+
1088
+ # what I need to do here now is to save in the folder of the parent à la TA --> can save it as neurons.tif maybe
1089
+
1090
+
1091
+
1092
+
1093
+ # def suppr_pressed(self):
1094
+ # # self.save_mask()
1095
+ # # print('suppr')
1096
+ # self.pa
1097
+
1098
+
1099
+ test = overriding_apply()
1100
+ test.vdp.shape_to_draw = Freehand2D
1101
+
1102
+ # test.vdp.shape_to_draw = Rect2D # ça ça marche --> bug is in the other then...
1103
+
1104
+ # there is a bug in the vectorial but no big deal probably
1105
+
1106
+ w = scrollable_paint(
1107
+ custom_paint_panel=test) # ça marche --> permet de mettre des paint panels avec des proprietes particulieres --> assez facile en fait
1108
+ # w.set_image('/E/Sample_images/sample_images_PA/mini (copie)/focused_Series012.png')
1109
+ # w.set_mask('/E/Sample_images/sample_images_PA/mini (copie)/focused_Series012/handCorrection.png')
1110
+ # w.set_image('/E/Sample_images/sample_images_PA/test_complete_wing_raphael/Optimized_projection_018.png')
1111
+ # w.set_mask('/E/Sample_images/sample_images_PA/test_complete_wing_raphael/neo_mask.tif')
1112
+
1113
+ test.vdp.active = True
1114
+ test.vdp.drawing_mode = True
1115
+
1116
+ # QApplication.setOverrideCursor(Qt.WaitCursor)
1117
+ # do lengthy process
1118
+ # QApplication.restoreOverrideCursor()
1119
+
1120
+ # w.set_image('/E/Sample_images/sample_images_FIJI/sample2.lsm')
1121
+ w.set_image('/E/Sample_images/sample_images_denoise_manue/29-1_lif/ON 290119.lif - Series001.tif')
1122
+
1123
+ # w.set_image('/E/Sample_images/sample_image_neurons_laurence_had/data_test/image.png')
1124
+ # w.set_mask('/D/VirtualBox/book_chapter_image_segmentation_final_2021/new_figs/dataset_1/minimal_demo_sample_simplified_bckup_before_messing_with_two_seg_errors/1/handCorrection.tif')
1125
+
1126
+ # w.setCursor(Qt.BlankCursor)
1127
+
1128
+ # ça marche mais tt finalizer
1129
+ # that seems to work
1130
+
1131
+ # w.freeze(True)
1132
+ # w.freeze(False)
1133
+ # w.freeze(True)
1134
+
1135
+ # we force the cursor to be visible --> set it by default
1136
+ # cursor = Qt.ArrowCursor
1137
+ # w.paint.setCursor(cursor)
1138
+
1139
+ # all is so easy to do this way
1140
+
1141
+ # ça marche --> tres facile a tester
1142
+ # --> how can I do a zoom
1143
+ # ask whether self scroll or not --> if scrollable
1144
+
1145
+ # mask = w.get_mask()
1146
+ #
1147
+ # plt.imshow(mask)
1148
+ # plt.show()
1149
+
1150
+ w.show()
1151
+ # w.setCursor(Qt.BlankCursor)
1152
+ sys.exit(app.exec_())