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