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,989 @@
1
+ # TODO need handle tracking and need break buttons to stop the loop
2
+ from batoolset.settings.global_settings import set_UI # set the UI to qtpy
3
+ set_UI()# none of the label drawings is great --> ignore t for now or maybe add it to the vectorial draw pane but do not allow edit and save of this and move it with the image!!!
4
+ import traceback
5
+ from functools import partial
6
+ import numpy as np
7
+ from qtpy import QtWidgets, QtGui, QtCore
8
+ from qtpy.QtCore import QRect, Qt, QSize
9
+ from qtpy.QtGui import QPalette
10
+ from qtpy.QtWidgets import QApplication, QGridLayout, QScrollArea, QLabel, QVBoxLayout, QDialog, QStyle, \
11
+ QStyleOptionTitleBar, QMessageBox, QDialogButtonBox
12
+ # from deprecated_demos.ta.wshed import Wshed
13
+ from batoolset.ta.segmentation.neo_wshed import wshed
14
+ # from batoolset.draw.widgets.paint import Createpaintwidget
15
+ from batoolset.img import Img, RGB_to_int24
16
+ from batoolset.draw.shapes.rect2d import Rect2D
17
+
18
+ # TODO add shortcuts to zoom and so on so that I can handle it better
19
+ # TODO maybe store the raw image in it
20
+
21
+ # in fact that is maybe already what I want!!!
22
+ # but I may also want to draw on it with a pen --> should have everything
23
+
24
+ # draw_mode= None #'pen' #'rect'
25
+
26
+ # fit to window or not
27
+ # maybe whatever happens the scroll should fit to window size
28
+
29
+ # NB in TA that works exactly as I want it !!!
30
+
31
+
32
+ # ok I finally have it
33
+ # implement all the zooms, crops, etc...
34
+ # --> TODO
35
+
36
+
37
+ # TODO --> maybe add a title
38
+ # TODO maybe offer to set a title in setimage --> can be a good idea
39
+ # faire un get image also
40
+ # faire un get mask
41
+ # ...
42
+ # faire un get shapes --> pas mal
43
+ # peut etre aussi permettre le right click pr supprimer des images
44
+
45
+
46
+ # TODO allow scroll all or zoom all at the same time or not!!!
47
+ # TODO allow support for shortcuts
48
+ # if sync shortcuts are for all, if not they are for the in focus stuff --> TODO
49
+
50
+ # vraiment tres bon mais à finaliser!!!
51
+
52
+ # TODO add labels --> would be really cool in a way
53
+ # maybe also add labels on the image ???
54
+
55
+ # TODO allow add labels on the sides --> like a table --> can be really useful!!!
56
+ from batoolset.GUI.paint2 import Createpaintwidget
57
+ from batoolset.ta.tracking.local_to_track_correspondance import add_localID_to_trackID_correspondance_in_DB
58
+ from batoolset.files.tools import smart_name_parser
59
+ from batoolset.ta.tracking.track_correction import swap_tracks, connect_tracks
60
+ from batoolset.tools.logger import TA_logger # logging
61
+
62
+ logger = TA_logger()
63
+
64
+ class ImgDisplayWindow(QDialog):
65
+
66
+ # replace preview only by a drawing mode --> TODO
67
+ # TODO try several displays at once then sync all
68
+ def __init__(self, parent_window=None, draw_mode=None, default_width=512, default_height=512, nb_rows=1, nb_cols=1,
69
+ synced=True , lst=None, cur_frame_idx=None):
70
+ super().__init__(parent=parent_window)
71
+ self.default_width = default_width
72
+ self.default_height = default_height
73
+ self.nb_rows = nb_rows
74
+ self.nb_cols = nb_cols
75
+ self.draw_mode = draw_mode
76
+ self.synced = synced
77
+ self.initUI()
78
+ self.lst = lst
79
+ self.cur_frame_idx = cur_frame_idx
80
+
81
+ # self.last_propagated_mouse_event = None
82
+
83
+ # override the QDialoog keyPressEvent to prevent it from stealing the return key from the drawing panels
84
+ def keyPressEvent(self, event):
85
+
86
+ # print('key intercepted ') # can I pass it to the paint in focus ??? next ????
87
+
88
+ if event.key() in (Qt.Key_Return, Qt.Key_Enter):
89
+ self.apply()
90
+ return
91
+
92
+
93
+ #
94
+ # else:
95
+ #
96
+ # print('in there')
97
+ # idx = self.get_idx_of_widget_under_mouse()
98
+ # # dirty hack to transfer shortcut to child
99
+ # if idx != -1:
100
+ # print('passing')
101
+ # # print('applying in', idx)
102
+ # if idx in [0,1,2]:
103
+ # print('forwarding')
104
+ # self.paints[idx].keyPressEvent(event)
105
+ super().keyPressEvent(event)
106
+
107
+ def initUI(self):
108
+ self.is_width_for_alternating = True
109
+ self.scale = 1.0
110
+ self.scroll_areas = []
111
+ self.paints = []
112
+ self.labels = []
113
+ # TODO should I also store the labels ???
114
+
115
+ layout = QGridLayout()
116
+ layout.setSpacing(0)
117
+ layout.setContentsMargins(0, 0, 0, 0)
118
+
119
+ # maybe set one master that can propagate the event to all others
120
+
121
+ # TODO draw a label directly on the scrollpane --> need override its paint method
122
+ # if self.label is not None:
123
+ # # formato
124
+ # canvasPainter.setPen(QColor("Green"))
125
+ # canvasPainter.setFont(QFont('Helvetica', 48))
126
+ # print('drawing text')
127
+ # canvasPainter.drawText(50, 50, self.label)
128
+
129
+ for jjj in range(self.nb_rows):
130
+ for iii in range(self.nb_cols):
131
+
132
+ # ça marche pas mal est ce plus simple outside ????
133
+ # or add a label directly on the image at various position just by drawing it in the paint window --> can also be very interesting!!!
134
+ main_container = QVBoxLayout()
135
+ # need store this in arrays
136
+ # scrollArea = QScrollArea()
137
+ scrollArea = QScrollArea()
138
+
139
+ # maybe add a vertical stuff above
140
+
141
+ # try add a Qlabel on top of it to label things up
142
+
143
+ label = QLabel('')
144
+ self.labels.append(label)
145
+
146
+ scrollArea.setHorizontalScrollBarPolicy(Qt.ScrollBarAsNeeded)
147
+ scrollArea.setVerticalScrollBarPolicy(Qt.ScrollBarAsNeeded)
148
+
149
+ # ui->scrollArea->verticalScrollBar()->isVisible();
150
+ # self.setMouseTracking(not self.preview_only) # I was doing crazy stuff here --> rather keep the draing mode in the inner object --> much simpler to handle
151
+
152
+ paint = Createpaintwidget()
153
+
154
+
155
+ paint.vdp.active = False
156
+ paint.vdp.drawing_mode = True
157
+
158
+ paint.force_cursor_visible = True # required to force activate cursor to be visible
159
+ if self.synced:
160
+ paint.propagate_mouse_move = True
161
+ paint.propagate_mouse_event = self.mouse_move_multihandler
162
+
163
+ # code to override apply
164
+ if True:
165
+ if jjj == 0:
166
+ # save a function with its partial
167
+ paint.apply = partial(self.custom_apply, paint)
168
+ elif jjj == 1:
169
+ paint.apply = partial(self.get_colors_drawn_over, paint)
170
+ else:
171
+ paint.vdp.drawing_mode = False
172
+
173
+
174
+ if self.draw_mode == 'rect':
175
+ paint.vdp.active = True
176
+ paint.vdp.shape_to_draw = Rect2D
177
+ # removing this makes it paint drawable --> really easy in fact
178
+ # print(self.draw_mode is not None)
179
+ paint.setMouseTracking(self.draw_mode is not None) # KEEP IMPORTANT
180
+ paint.drawing = False # is that useful, I don't like it --> make it better
181
+
182
+ # print(self.paint.hasMouseTracking())
183
+ # self.paint.drawing = False # why always true
184
+ # self.paint.mouseMoveEvent = self.mouseMoveEvent
185
+ # self.paint.mousePressEvent = self.mousePressEvent
186
+ # self.paint.mouseReleaseEvent = self.mouseReleaseEvent
187
+
188
+ # self.prev_width = 192
189
+ # self.prev_height = 192
190
+
191
+ scrollArea.setGeometry(QRect(0, 0, self.default_width, self.default_height))
192
+ scrollArea.setBackgroundRole(QPalette.Dark)
193
+ scrollArea.setWidgetResizable(
194
+ False) # allows it to resize when the parent window is resized --> force a new repaint
195
+
196
+ if self.synced:
197
+ scrollArea.verticalScrollBar().valueChanged.connect(self.scroll_vertically_together)
198
+ scrollArea.horizontalScrollBar().valueChanged.connect(self.scroll_horizontally_together)
199
+
200
+ scrollArea.setWidget(paint)
201
+ paint.scrollArea = scrollArea
202
+ # self.paint.setBaseSize(512,512)
203
+
204
+ self.scroll_areas.append(scrollArea)
205
+ self.paints.append(paint)
206
+
207
+ self.setGeometry(QRect(0, 0, self.default_width, self.default_height))
208
+
209
+ main_container.addWidget(label)
210
+ main_container.addWidget(scrollArea)
211
+
212
+ # layout.addWidget(scrollArea,jjj,iii)
213
+ layout.addLayout(main_container, jjj, iii)
214
+ # self.setFixedSize(self.size()) # I actually want it resizable and upon resize change image size accordingly
215
+
216
+ # see how to define scrollarea size in the window --> that is really key though --> I think I have a bug maybe check in top TA
217
+ # add shortcuts --> needs love
218
+ # if self.synced:
219
+ self.add_shortcuts() # ça marche --> mais à améliorer if in sync remove self stuff
220
+ self.buttonBox = QDialogButtonBox(QDialogButtonBox.Ok | QDialogButtonBox.Cancel)
221
+
222
+ # dirty way of doing this but ok!!!
223
+ self.buttonBox.button(QDialogButtonBox.Ok).setText("Next")
224
+ self.buttonBox.button(QDialogButtonBox.Cancel).setText("Stop")
225
+
226
+ self.buttonBox.accepted.connect(self.accept_if_clicked)
227
+ self.buttonBox.rejected.connect(self.reject)
228
+
229
+
230
+
231
+ # self.buttonBox.button(QDialogButtonBox.Ok).setAutoDefault(False)
232
+ # self.buttonBox.button(QDialogButtonBox.Cancel).setAutoDefault(False)
233
+ # self.buttonBox.button(QDialogButtonBox.Ok).setDefault(False)
234
+ # self.buttonBox.button(QDialogButtonBox.Cancel).setDefault(False)
235
+
236
+
237
+
238
+ layout.addWidget(self.buttonBox)
239
+
240
+ self.setLayout(layout)
241
+
242
+ # dirty hack to ignore enter pressed
243
+ def accept_if_clicked(self):
244
+ if not self.buttonBox.button(QDialogButtonBox.Ok).hasFocus():
245
+ return
246
+ return self.accept()
247
+
248
+
249
+ def get_colors_drawn_over(self, paint):
250
+ mask = paint.get_user_drawing()
251
+ # print('I was called')
252
+ if mask is None:
253
+ return
254
+ # print(mask)
255
+
256
+
257
+ # need get all the colors of the raw image that correspond to user selection
258
+ selected_colors =paint.get_raw_image()[mask!=0]
259
+ selected_colors = RGB_to_int24(selected_colors)
260
+
261
+ selected_colors =set(selected_colors.ravel().tolist())
262
+ if 0xFFFFFF in selected_colors:
263
+ selected_colors.remove(0xFFFFFF)
264
+ selected_colors = list(selected_colors)
265
+
266
+ # print('colors', selected_colors) #.ravel()
267
+ #neee=d get the colors as RGB single values --> convert the output to RGB
268
+
269
+
270
+
271
+ # ned convert to
272
+
273
+
274
+ # plt.imshow(mask)
275
+ # plt.show()
276
+
277
+ # paint.set_mask(None)# reset the mask
278
+ # paint.set_mask(None)
279
+ # paint.reset_user_drawing()
280
+ # paint.raw_user_drawing.fill(QtCore.Qt.transparent)
281
+
282
+ # this is the only way I found to reset the user drawing but this is dirty and I must find a better way
283
+ paint.set_mask(np.zeros_like(mask))
284
+
285
+
286
+ # marche pas...Why ?
287
+ # paint.raw_user_drawing = QtGui.QImage(paint.imageDraw.size(), QtGui.QImage.Format_ARGB32)
288
+ # paint.raw_user_drawing.fill(QtCore.Qt.transparent) # somehow this is really required to have an empty image otherwise it is not --> ??? why
289
+
290
+ # test = paint.get_user_drawing()
291
+ # plt.imshow(test)
292
+ # plt.show()
293
+ # update drawing after user input has been reset
294
+
295
+ paint.update()
296
+ return selected_colors
297
+
298
+ def custom_apply(self, paint):
299
+ # print('you called me', paint, filename)
300
+ # print(QtGui.QImageWriter.supportedImageFormats())
301
+ # save as tiff ???
302
+
303
+ # drawn_img = paint.imageDraw
304
+
305
+ # ça marche mais c'est vraiment juste le dessin --> faudrait donc que je passe le masque entier en mask et pas seulement ça --> voir ds TA comment faire en fait et aussi faire que le mask et le wshed tourne là dedans en fait car smarter
306
+
307
+ # drawn_img.save("/E/Sample_images/sample_images_PA/trash/image.png", "PNG", -1)
308
+ # drawn_img.save("/E/Sample_images/sample_images_PA/trash/image.tif", "TIF", -1)
309
+ # print('saving',"/E/Sample_images/sample_images_PA/trash/image.tif")
310
+ # print(drawn_img)
311
+
312
+ # nb will only work for red pen !!!! --> do not allow to change pen color
313
+ mask = paint.get_mask()
314
+ if mask is None:
315
+ return
316
+ # TODO would need to run the wshed on it --> finally fix or recode my wshed can be done with numba
317
+
318
+ # ça marche en fait maintenant --> utiliser ça du coup!!!
319
+ # d'ailleurs verif ce code et le nettoyer une bonne fois pr toute et le mettre dans paint et dans mask d'ailleurs...
320
+ # if nothing is saved image become compeletely full of white
321
+ mask = wshed(mask, seeds='mask')
322
+
323
+ # print('saving filename',filename)
324
+ # plt.imshow(mask[...,2])
325
+ # plt.show()
326
+ # Img(mask, dimensions='hw').save(filename)
327
+
328
+ # update the mask
329
+ # nb maybe only save on demand each ??? --> think what is the best way to do that
330
+ paint.set_mask(mask)
331
+
332
+
333
+ # Img(img, dimensions='hwc').save(filename, mode='raw')
334
+
335
+ def mouse_move_multihandler(self, event):
336
+ # pb is I need get the sender not to send it it all
337
+ # very dirty and infinite loop --> see how to do that for all
338
+ # print('toto', self, event)
339
+ # just get it to draw the cursor --> no infinite propagation then
340
+ # if event == self.last_propagated_mouse_event:
341
+ # return
342
+ # idx = self.get_idx_of_widget_under_mouse()
343
+ # print(idx)
344
+ # copied_event = event
345
+ # if event.type() == QEvent.MouseMove:
346
+ # copied_event = event.pos()
347
+ # copied_event = event.copy()
348
+
349
+ # copied_event = QMouseEvent()
350
+ # self.receiver.move(event.pos())
351
+ for iii, paint in enumerate(self.paints):
352
+ try:
353
+ # if iii != idx:
354
+ # MEGA TODO: SUPER ULTIMATE DIRTY HACK FOR MOUSE EVENT PROPAGATION THROUGH PAINT WIDGETS THINK ABOUT A SMARTER WAY TO DO THAT IN THE FUTURE yet ok for now...
355
+ paint.propagate_mouse_move = False
356
+ # paint.mouseMove(copied_event) #Event( event)
357
+ # paint.mouseMoveEvent(copied_event) #Event( event)
358
+ paint.mouseMoveEvent(event) # Event( event)
359
+ paint.propagate_mouse_move = True
360
+ # self.last_propagated_mouse_event = event
361
+ except:
362
+ traceback.print_exc()
363
+ pass
364
+
365
+
366
+ # could add the same shortcuts within individual panels
367
+ def add_shortcuts(self):
368
+ # if True:
369
+ # return
370
+ zoomPlus = QtWidgets.QShortcut("Ctrl+Shift+=", self)
371
+ zoomPlus.activated.connect(self.zoomIn)
372
+ zoomPlus.setContext(QtCore.Qt.ApplicationShortcut)
373
+
374
+ zoomPlus2 = QtWidgets.QShortcut("Ctrl++", self)
375
+ zoomPlus2.activated.connect(self.zoomIn)
376
+ zoomPlus2.setContext(QtCore.Qt.ApplicationShortcut)
377
+
378
+ zoomMinus = QtWidgets.QShortcut("Ctrl+Shift+-", self)
379
+ zoomMinus.activated.connect(self.zoomOut)
380
+ zoomMinus.setContext(QtCore.Qt.ApplicationShortcut)
381
+
382
+ zoomMinus2 = QtWidgets.QShortcut("Ctrl+-", self)
383
+ zoomMinus2.activated.connect(self.zoomOut)
384
+ zoomMinus2.setContext(QtCore.Qt.ApplicationShortcut)
385
+
386
+ # dirty reimplementation of the shortcuts --> TODO recode that better some day --> but ok for now
387
+ enterShortcut = QtWidgets.QShortcut(QtGui.QKeySequence(QtCore.Qt.Key_Return), self)
388
+ enterShortcut.activated.connect(self.apply)
389
+ enterShortcut.setContext(QtCore.Qt.ApplicationShortcut)
390
+
391
+ enterShortcut2 = QtWidgets.QShortcut(QtGui.QKeySequence(QtCore.Qt.Key_Enter), self)
392
+ enterShortcut2.activated.connect(self.apply)
393
+ enterShortcut2.setContext(QtCore.Qt.ApplicationShortcut)
394
+
395
+ shrtM = QtWidgets.QShortcut("M", self)
396
+ shrtM.activated.connect(self.m_apply)
397
+ shrtM.setContext(QtCore.Qt.ApplicationShortcut)
398
+
399
+ ctrlM = QtWidgets.QShortcut("Ctrl+M", self)
400
+ ctrlM.activated.connect(self.ctrl_m_apply)
401
+ ctrlM.setContext(QtCore.Qt.ApplicationShortcut)
402
+
403
+ # pkoi ça ne marche pas !!!
404
+ shiftEnterShortcut = QtWidgets.QShortcut("Shift+Enter", self)
405
+ shiftEnterShortcut.activated.connect(self.shift_apply)
406
+ shiftEnterShortcut.setContext(QtCore.Qt.ApplicationShortcut)
407
+ #
408
+ shiftEnterShortcut2 = QtWidgets.QShortcut("Shift+Return", self)
409
+ shiftEnterShortcut2.activated.connect(self.shift_apply)
410
+ shiftEnterShortcut2.setContext(QtCore.Qt.ApplicationShortcut)
411
+
412
+
413
+
414
+ def take_intelligent_decision_for_track_editing_based_on_user_selection(self, selected_cells_prev, selected_cells_cur, selected_cells_next):
415
+ # if selected_cells_prev is not None and selected_cells_prev:
416
+ # # check how many cells have been selected and take action depending in the stuff
417
+ # pass
418
+ # if selected_cells_cur is not None and selected_cells_cur:
419
+ # pass
420
+ # if selected_cells_next is not None and selected_cells_next:
421
+ # pass
422
+ if selected_cells_next is None:
423
+ selected_cells_next = []
424
+ if selected_cells_prev is None:
425
+ selected_cells_prev = []
426
+ if selected_cells_cur is None:
427
+ selected_cells_cur = []
428
+
429
+ if len(selected_cells_prev) + len(selected_cells_cur) + len(selected_cells_next) != 2:
430
+ # print('Error: ')
431
+ if len(selected_cells_prev) + len(selected_cells_cur) + len(selected_cells_next) < 2:
432
+ # not enough cells --> need add more
433
+ self._show_warning_msage(text='Not enough cells drawn over, please click on exactly two cells')
434
+ return
435
+
436
+ # print(len(selected_cells_prev) + len(selected_cells_cur) + len(selected_cells_next))
437
+ # print(selected_cells_next, selected_cells_prev, selected_cells_cur)
438
+ self._show_warning_msage()
439
+ return
440
+
441
+ # the user has drawn properly over the image --> some decision can be taken then
442
+ # --> do the stuff
443
+
444
+ # sqsqdsqsqdqsdqsdqsd
445
+
446
+ # if both are in the same then do swap otherwise try connect cells
447
+ # I also need to know the current frame --> TODO
448
+
449
+ # I need have the list and the current frame
450
+
451
+ try:
452
+ path_to_cur_track = smart_name_parser(self.lst[self.cur_frame_idx], 'tracked_cells_resized.tif')
453
+ except:
454
+ path_to_cur_track = None
455
+ try:
456
+ path_to_next_track = smart_name_parser(self.lst[self.cur_frame_idx+1], 'tracked_cells_resized.tif')
457
+ except:
458
+ path_to_next_track = None
459
+ try:
460
+ path_to_prev_track = smart_name_parser(self.lst[self.cur_frame_idx-1], 'tracked_cells_resized.tif')
461
+ except:
462
+ path_to_prev_track = None
463
+
464
+ something_changed = False
465
+ if len(selected_cells_cur) == 2:
466
+ # launch a swap starting from the current image onwards
467
+ # start swapping fropm current idx onwards
468
+ something_changed = True
469
+ swap_tracks(self.lst, self.cur_frame_idx, selected_cells_cur[0],selected_cells_cur[1])
470
+ # check the images that need be reloaded and update them
471
+ # I need update cur and next image
472
+ if path_to_cur_track is not None:
473
+ img = Img(path_to_cur_track)
474
+ self.paints[4].set_image(img)
475
+ if path_to_next_track is not None:
476
+ img = Img(path_to_next_track)
477
+ self.paints[5].set_image(img)
478
+
479
+ # need reload two images
480
+ if len(selected_cells_next) == 2:
481
+ something_changed = True
482
+ swap_tracks(self.lst, self.cur_frame_idx+1, selected_cells_next[0], selected_cells_next[1])
483
+
484
+ if path_to_next_track is not None:
485
+ img = Img(path_to_next_track)
486
+ self.paints[5].set_image(img)
487
+
488
+ if len(selected_cells_prev) == 2:
489
+ something_changed = True
490
+ swap_tracks(self.lst, self.cur_frame_idx-1, selected_cells_prev[0], selected_cells_prev[1])
491
+
492
+ if path_to_prev_track is not None:
493
+ img = Img(path_to_prev_track)
494
+ self.paints[3].set_image(img)
495
+ if path_to_cur_track is not None:
496
+ img = Img(path_to_cur_track)
497
+ self.paints[4].set_image(img)
498
+ if path_to_next_track is not None:
499
+ img = Img(path_to_next_track)
500
+ self.paints[5].set_image(img)
501
+
502
+
503
+ if len(selected_cells_cur)==1:
504
+ if len(selected_cells_prev)==1:
505
+ something_changed = True
506
+ connect_tracks(self.lst, self.cur_frame_idx, selected_cells_cur[0],selected_cells_prev[0])
507
+ if path_to_cur_track is not None:
508
+ img = Img(path_to_cur_track)
509
+ self.paints[4].set_image(img)
510
+ if path_to_next_track is not None:
511
+ img = Img(path_to_next_track)
512
+ self.paints[5].set_image(img)
513
+
514
+ if len(selected_cells_next)==1:
515
+ something_changed = True
516
+ connect_tracks(self.lst, self.cur_frame_idx+1, selected_cells_cur[0],selected_cells_next[0])
517
+
518
+ if path_to_next_track is not None:
519
+ img = Img(path_to_next_track)
520
+ self.paints[5].set_image(img)
521
+ else:
522
+ logger.error('Please try to connect tracks across two consecutive frames, not between images distant from one another')
523
+
524
+ # TODO better check the something changed to avoid unnecessary db updates that may be lengthy
525
+ if something_changed:
526
+ # need update the track to local ID correpsondace
527
+ add_localID_to_trackID_correspondance_in_DB(self.lst)
528
+
529
+
530
+
531
+ def shift_apply(self):
532
+ idx = self.get_idx_of_widget_under_mouse()
533
+ # dirty hack to transfer shortcut to child
534
+ if idx != -1:
535
+ # print('applying in', idx)
536
+ if idx in [0,1,2]:
537
+ self.paints[idx].apply_drawing(minimal_cell_size=10)
538
+
539
+
540
+ # full of bugs --> deactivate it here ????
541
+ def ctrl_m_apply(self):
542
+ idx = self.get_idx_of_widget_under_mouse()
543
+ # dirty hack to transfer shortcut to child
544
+ if idx != -1:
545
+ # print('applying in', idx)
546
+ if idx in [0, 1, 2]:
547
+ try:
548
+ self.paints[idx].manually_reseeded_wshed()
549
+ except:
550
+ traceback.print_exc()
551
+
552
+
553
+ def m_apply(self):
554
+ idx = self.get_idx_of_widget_under_mouse()
555
+ # dirty hack to transfer shortcut to child
556
+ if idx != -1:
557
+ # print('applying in', idx)
558
+ if idx in [0,1,2]:
559
+ self.paints[idx].m_apply()
560
+
561
+
562
+
563
+
564
+ # ça marche mais c'est super dirty je pense ???? en plus pr je ne sais quelle raison marche pas avec enter
565
+ # ça fera
566
+ def apply(self):
567
+ # print('apply method to override in main')
568
+ idx = self.get_idx_of_widget_under_mouse()
569
+ # dirty hack to transfer shortcut to child
570
+ if idx != -1:
571
+ # print('applying in', idx)
572
+ if idx not in [3,4,5]:
573
+ self.paints[idx].apply()
574
+ else:
575
+ # get swaps from all the images and take action if makes sense
576
+ # or warn for errors
577
+ selected_cells_prev = []
578
+ selected_cells_cur = []
579
+ selected_cells_next = []
580
+ if len(self.paints) >= 4:
581
+ selected_cells_prev = self.paints[3].apply()
582
+ if len(self.paints) >= 5:
583
+ selected_cells_cur = self.paints[4].apply()
584
+ if len(self.paints) >= 6:
585
+ selected_cells_next = self.paints[5].apply()
586
+
587
+ self.take_intelligent_decision_for_track_editing_based_on_user_selection(selected_cells_prev, selected_cells_cur, selected_cells_next)
588
+
589
+ def _show_warning_msage(self, text='Too many cells for track correction please just draw over two cells, no more...'):
590
+ msg = QMessageBox()
591
+ msg.setIcon(QMessageBox.Critical)
592
+ msg.setText("Error")
593
+ msg.setInformativeText(text)
594
+ msg.setWindowTitle("Error")
595
+ # msg.setDetailedText("Detailed explanation of the error: .......") # TODO maybe add more some day
596
+ retval = msg.exec_()
597
+ # in case I would need to do something with the retval but I gss I do
598
+
599
+
600
+ # print()
601
+ # allows the bars to scroll together --> quite good in fact
602
+ # do it also for horiz
603
+ def scroll_vertically_together(self, event):
604
+ # print(event)
605
+ for scrollbar in self.scroll_areas:
606
+ scrollbar.verticalScrollBar().setValue(event)
607
+
608
+ def scroll_horizontally_together(self, event):
609
+ # print(event)
610
+ for scrollbar in self.scroll_areas:
611
+ scrollbar.horizontalScrollBar().setValue(event)
612
+
613
+ def set_labels(self, *args):
614
+ for iii, label in enumerate(args):
615
+ self.set_label(label, nb=iii)
616
+
617
+ def set_images(self, *args):
618
+ for iii, img in enumerate(args):
619
+ self.set_image(img, nb=iii)
620
+
621
+ def set_label(self, label, nb=0):
622
+ if label is not None:
623
+ self.labels[nb].setText(label)
624
+ else:
625
+ self.labels[nb].setText('')
626
+ # paint = self.paints[nb]
627
+ # paint.vdp.shapes.clear()
628
+ # paint.set_image(img) # bug is here
629
+ # if img is None:
630
+ # paint.scale = self.scale = paint.vdp.scale = 1. # will that work ??? remove global scale ???
631
+ # else:
632
+ # max_size = min(self.prev_width / img.get_width(), self.prev_height / img.get_height())
633
+ # self.paint.scale = self.scale = self.paint.vdp.scale = max_size
634
+
635
+ # TODO handle scale nicely here
636
+ # also allow drawing over the image
637
+
638
+ # if paint.image is not None:
639
+ # paint.resize(self.scale * paint.image.size())
640
+ # self.scrollArea.resize(self.scale * self.paint.image.size())
641
+ # self.scrollArea.resize(self.size())
642
+
643
+ # print('self.paint.hasMouseTracking()', self.paint.hasMouseTracking())# how come it can track if no mouse tracking ???
644
+
645
+
646
+
647
+ # should I offer a crop of the image --> maybe also make it to store the relevant raw data --> can be very useful
648
+ # do a clear also for the image
649
+ def set_image(self, img, nb=0):
650
+
651
+ paint = self.paints[nb]
652
+ paint.vdp.shapes.clear()
653
+ paint.set_image(img) # bug is here
654
+ if img is None:
655
+ paint.scale = self.scale = paint.vdp.scale = 1. # will that work ??? remove global scale ???
656
+ # else:
657
+ # max_size = min(self.prev_width / img.get_width(), self.prev_height / img.get_height())
658
+ # self.paint.scale = self.scale = self.paint.vdp.scale = max_size
659
+
660
+ # TODO handle scale nicely here
661
+ # also allow drawing over the image
662
+
663
+ if paint.image is not None:
664
+ paint.resize(self.scale * paint.image.size())
665
+ # self.scrollArea.resize(self.scale * self.paint.image.size())
666
+ # self.scrollArea.resize(self.size())
667
+
668
+ # print('self.paint.hasMouseTracking()', self.paint.hasMouseTracking())# how come it can track if no mouse tracking ???
669
+
670
+
671
+
672
+ # clear image
673
+ def clear(self, nb=0):
674
+ self.set_image(None, nb=nb)
675
+ # print(self.size())
676
+ # self.scrollArea.resize(self.size())
677
+ size = self.size()
678
+ scrollArea = self.scroll_areas[nb]
679
+ scrollArea.setGeometry(QRect(0, 0, size.width(), size.height()))
680
+ paint = self.paints[nb]
681
+ paint.setGeometry(
682
+ QRect(0, 0, self.default_width - 2, self.default_height - 2)) # force all black and no scrollbars ---> ok
683
+ # self.scale = 1.
684
+
685
+ # ça marche --> ajouter fit to width ou fit to height
686
+ def fit_to_width_or_height(self):
687
+ if self.is_width_for_alternating:
688
+ self.fit_to_width()
689
+ else:
690
+ self.fit_to_height()
691
+ self.is_width_for_alternating = not self.is_width_for_alternating
692
+
693
+ # almost there but small bugs
694
+ def fit_to_width(self, nb=0):
695
+ paint = self.paints[nb]
696
+ if paint.image is None:
697
+ return
698
+ scrollArea = self.scroll_areas[nb]
699
+ width = scrollArea.width() - 2
700
+ width -= scrollArea.verticalScrollBar().sizeHint().width()
701
+ # height-=self.scrollArea.horizontalScrollBar().sizeHint().height()
702
+ width_im = paint.image.width()
703
+ scale = width / width_im
704
+ self.scaleImage(scale, nb=nb)
705
+
706
+ def fit_to_height(self, nb=0):
707
+ paint = self.paints[nb]
708
+ if paint.image is None:
709
+ return
710
+ scrollArea = self.scroll_areas[nb]
711
+ height = scrollArea.height() - 2
712
+ height -= scrollArea.horizontalScrollBar().sizeHint().height()
713
+ height_im = paint.image.height()
714
+ scale = height / height_im
715
+ self.scaleImage(scale, nb=nb)
716
+
717
+ def fit_to_window(self, nb=0):
718
+ # compute best fit
719
+ # just get the size of the stuff and best fit it
720
+ paint = self.paints[nb]
721
+ if paint.image is None:
722
+ return
723
+
724
+ # QScrollArea.ensureWidgetVisible(
725
+ # QScrollArea.ensureVisible
726
+ # QScrollArea.setWidgetResizable
727
+ scrollArea = self.scroll_areas[nb]
728
+ width = scrollArea.width() - 2 # required to make sure bars not visible
729
+ height = scrollArea.height() - 2
730
+
731
+ # scale image that it fits in --> change scale
732
+
733
+ # width-=self.scrollArea.verticalScrollBar().sizeHint().width()
734
+ # height-=self.scrollArea.horizontalScrollBar().sizeHint().height()
735
+
736
+ height_im = paint.image.height()
737
+ width_im = paint.image.width()
738
+ scale = height / height_im
739
+ if width / width_im < scale:
740
+ scale = width / width_im
741
+ self.scaleImage(scale, nb=nb)
742
+
743
+ # don't want a factor
744
+ def scaleImage(self, scale, nb=0):
745
+ paint = self.paints[nb]
746
+ self.scale = scale
747
+ if paint.image is not None:
748
+ paint.resize(self.scale * paint.image.size())
749
+ else:
750
+ # no image set size to 0, 0 --> scroll pane will auto adjust
751
+ paint.resize(QSize(0, 0))
752
+ # self.scale -= factor # reset zoom
753
+
754
+ paint.scale = self.scale
755
+ paint.vdp.scale = self.scale
756
+ paint.update()
757
+
758
+ # self.adjustScrollBar(self.scrollArea.horizontalScrollBar(), factor)
759
+ # self.adjustScrollBar(self.scrollArea.verticalScrollBar(), factor)
760
+
761
+ # self.zoomInAct.setEnabled(self.scale < self.max_scaling_factor)
762
+ # self.zoomOutAct.setEnabled(self.scale > self.min_scaling_factor)
763
+
764
+ # synced version of scale
765
+ def scale_image_all(self, scale):
766
+ for img_nb in range(len(self.paints)):
767
+ self.scaleImage(scale, nb=img_nb)
768
+
769
+ #
770
+ # def fitToWindow(self):
771
+ # # TODO most likely a bug there because calls self.defaultSize that resets the scale --> MAKE NO SENSE
772
+ # fitToWindow = self.fitToWindowAct.isChecked()
773
+ # self.scrollArea.setWidgetResizable(fitToWindow)
774
+ # if not fitToWindow:
775
+ # self.defaultSize()
776
+
777
+ def zoomIn(self):
778
+ if self.synced:
779
+ self.scale_image_all(scale=self.scale + 0.1)
780
+ else:
781
+ idx = self.get_idx_of_widget_under_mouse()
782
+ if idx != -1:
783
+ self.scaleImage(self.scale + 0.1, nb=idx)
784
+ # get index
785
+
786
+ def zoomOut(self):
787
+ if self.synced:
788
+ self.scale_image_all(scale=self.scale - 0.1)
789
+ else:
790
+ idx = self.get_idx_of_widget_under_mouse()
791
+ if idx != -1:
792
+ self.scaleImage(self.scale - 0.1, nb=idx)
793
+
794
+ # get the index of the image under the mouse!!
795
+ def get_idx_of_widget_under_mouse(self):
796
+ pos = QtGui.QCursor.pos()
797
+ widget = QApplication.widgetAt(pos)
798
+ for iii, paint in enumerate(self.paints):
799
+ if widget == paint:
800
+ return iii
801
+ for iii, scrollarea in enumerate(self.scroll_areas):
802
+ if widget == scrollarea:
803
+ return iii
804
+ return -1
805
+
806
+ def get_paints(self):
807
+ return self.paints
808
+
809
+ @staticmethod
810
+ def display(parent=None, draw_mode=None, default_width=512, default_height=512, nb_rows=1, nb_cols=1, synced=True,
811
+ images=None, labels=None, lst=None, cur_frame_idx=None):
812
+
813
+
814
+ dialog = ImgDisplayWindow(parent, draw_mode=draw_mode, default_width=default_width,
815
+ default_height=default_height, nb_cols=nb_cols, nb_rows=nb_rows, synced=synced, lst=lst, cur_frame_idx=cur_frame_idx)
816
+ # dialog.showFullScreen() # pas mal mais vraiùment full screen --> can cause trouble --> maybe change this some day
817
+
818
+
819
+ # show dialog full screen without maximizing, see # https://stackoverflow.com/questions/15702470/how-to-make-a-window-that-occupies-the-full-screen-without-maximising
820
+ titleBarHeight = dialog.style().pixelMetric(
821
+ QStyle.PM_TitleBarHeight,
822
+ QStyleOptionTitleBar(),
823
+ dialog
824
+ )
825
+
826
+ # geometry = app.desktop().availableGeometry()
827
+ # geometry = QtWidgets.QDesktopWidget().availableGeometry()
828
+ # geometry.setHeight(geometry.height() - (titleBarHeight*2))
829
+ try:
830
+ geometry = QtWidgets.QDesktopWidget().availableGeometry()
831
+ geometry.setHeight(geometry.height() - (titleBarHeight * 2))
832
+ except:
833
+ from qtpy.QtGui import QGuiApplication
834
+ geometry = QGuiApplication.primaryScreen().geometry()
835
+
836
+ dialog.setGeometry(geometry)
837
+ # end show full screen without maximizing
838
+
839
+ if images is not None:
840
+ dialog.set_images(*images)
841
+
842
+ if labels is not None:
843
+ dialog.set_labels(*labels)
844
+
845
+ result = dialog.exec_()
846
+ augment = dialog.get_paints()
847
+ return (augment, result == QDialog.Accepted)
848
+
849
+
850
+ # does not work
851
+ # class labelled_scrollarea(QScrollArea):
852
+ #
853
+ # def __init__(self):
854
+ # super().__init__()
855
+ #
856
+ # # def paintEvent(self, event):
857
+ # # # ne marche pas car l'autre truc ecrit par dessus
858
+ # # # super().paintEvent(event)
859
+ # # super(labelled_scrollarea, self).paintEvent(event)
860
+ # #
861
+ # # # self.viewport().paintEvent(event)
862
+ # # # pb the widget overrides that --> need first paint it then call that
863
+ # # # print('inside')
864
+ # # painter = QtGui.QPainter(self.viewport())
865
+ # # # this will never work here --> really need be done in the other painter
866
+ # #
867
+ # # # painter = QPainter()
868
+ # # # painter.begin(self.viewport())
869
+ # # # self.drawRectangles(qp)
870
+ # # # painter.end()
871
+ # #
872
+ # # # painter = QPainter(self.viewport()) # If a widget has a viewport, you have to pass that to the QPainter constructor: https://stackoverflow.com/questions/12226930/overriding-qpaintevents-in-pyqt
873
+ # # # painter = QPainter(self) # If a widget has a viewport, you have to pass that to the QPainter constructor: https://stackoverflow.com/questions/12226930/overriding-qpaintevents-in-pyqt
874
+ # # # painter.setRenderHint(QPainter.Antialiasing)
875
+ # # painter.setPen(Qt.darkRed)
876
+ # # rectangle = QRectF(10.0, 20.0, 80.0, 60.0)
877
+ # # painter.drawRect(rectangle)
878
+ # #
879
+ # # painter.setPen(QColor("Green"))
880
+ # # painter.setFont(QFont('Helvetica', 48))
881
+ # # # print('drawing text')
882
+ # # painter.drawText(50, 50, 'this is a test of your system')
883
+ # #
884
+ # # painter.end()
885
+ # #
886
+ # # # scrollArea.paintEvent = paintEvent
887
+
888
+
889
+ if __name__ == '__main__':
890
+ # TODO --> last thing todo is to apply several 'apply' methods for each of the paint methods --> maybe simply override them ???
891
+
892
+ # TODO allow unknown number of files, sort of on demand creation --> clear and restore all paints and scrolls
893
+ # move most of the commands to the image panel itself
894
+ # allow crops
895
+ # add shortcuts
896
+ # offer synchronous pointer maybe ???
897
+ # offer drift maybe ???
898
+ # store the image directly in the object --> much smarter and easier to retrieve (maybe handle Z and or t stacks also from within)
899
+ # would be perfect to see corrections
900
+ # for corrections maybe first do the human one fully then try to automate things with automated solutions with accept of reject à la tinder --> TODO
901
+ # already showing the three original images with masks, the three tracks and the scores with prev and next for the current as well as new and lost cells should do most of the job
902
+ # later I can try automated corrections but quite ok already
903
+ # NB IDEALLY THE SCALE SHOULD ALSO BE SAVED DIRECTLY IN THE THING THAT DISPLAYS IMAGES
904
+
905
+ if True:
906
+ # try open this as a dialog
907
+ import sys
908
+
909
+ app = QApplication(sys.argv)
910
+ # TODO find a way to synchronize the mouse for all
911
+
912
+ # find a way to propagate mouse events from one to all
913
+ # ok = ImgDisplayWindow.display(draw_mode='pen', nb_cols=5, images=[
914
+ # Img('/E/Sample_images/sample_images_PA/egg_chambers/120404_division_EcadKI.lif - Series006_RGB_manual_proj.png'),
915
+ # Img('/E/Sample_images/sample_images_PA/mini10_fake_swaps/focused_Series012.png'),
916
+ # Img('/E/Sample_images/sample_images_PA/egg_chambers/120404_division_EcadKI.lif - Series006_RGB_manual_proj.png'),
917
+ # Img('/E/Sample_images/sample_images_PA/mini10_fake_swaps/focused_Series012.png'), None])
918
+
919
+ lst = ['/E/Sample_images/sample_images_PA/mini_different_nb_of_channels/focused_Series012.png', '/E/Sample_images/sample_images_PA/mini_different_nb_of_channels/focused_Series014.png', '/E/Sample_images/sample_images_PA/mini_different_nb_of_channels/focused_Series016.png']
920
+
921
+ augment, ok = ImgDisplayWindow.display(draw_mode='pen', nb_rows=3, nb_cols=3, images=[
922
+ [Img('/E/Sample_images/sample_images_PA/mini_different_nb_of_channels/focused_Series012.png'),Img('/E/Sample_images/sample_images_PA/mini_different_nb_of_channels/focused_Series012/handCorrection.tif')],
923
+ Img('/E/Sample_images/sample_images_PA/mini_different_nb_of_channels/focused_Series014.png'),
924
+ Img('/E/Sample_images/sample_images_PA/mini_different_nb_of_channels/focused_Series016.png'),
925
+ Img('/E/Sample_images/sample_images_PA/mini_different_nb_of_channels/focused_Series012/tracked_cells_resized.tif'),
926
+ Img('/E/Sample_images/sample_images_PA/mini_different_nb_of_channels/focused_Series014/tracked_cells_resized.tif'),
927
+ Img('/E/Sample_images/sample_images_PA/mini_different_nb_of_channels/focused_Series016/tracked_cells_resized.tif'), None],
928
+ labels=['test1', 'test2', 'test3', None], lst=lst, cur_frame_idx=1)
929
+ print(augment, ok)
930
+ sys.exit(0)
931
+
932
+ if False:
933
+ # pas
934
+
935
+ # TODO essayer le multidisplay
936
+ # avec un set pr bcp de choses
937
+
938
+ # ok in fact that is already a great popup window --> can I further improve it ???
939
+
940
+ # just for a test
941
+ app = QApplication(sys.argv)
942
+ ex = ImgDisplayWindow(nb_rows=2, nb_cols=2)
943
+ # ex = ImgDisplayWindow(preview_only=True)
944
+ # img = Img('/home/aigouy/mon_prog/Python/Deep_learning/unet/data/membrane/test/11.png')
945
+ # img = Img('/home/aigouy/mon_prog/Python/Deep_learning/unet/data/membrane/test/122.png')
946
+ # img = Img('/home/aigouy/mon_prog/Python/data/3D_bicolor_ovipo.tif')
947
+ # img = Img('/home/aigouy/mon_prog/Python/data/Image11.lsm')
948
+ # img = Img('/home/aigouy/mon_prog/Python/data/lion.jpeg')
949
+ # img = Img('/home/aigouy/mon_prog/Python/data/epi_test.png')
950
+
951
+ img = Img(
952
+ '/E/Sample_images/sample_images_PA/egg_chambers/120404_division_EcadKI.lif - Series006_RGB_manual_proj.png')
953
+ ex.set_image(img)
954
+
955
+ # test = QRectF(None, None, 128, 128)
956
+ ex.scaleImage(
957
+ 22) # ça marche faudra finalizer des trucs mais pas mal déjà --> tt mettre en interne dans ma classe d'intéret --> I'm almost done
958
+ # store image inside and also give it more options
959
+ ex.fit_to_window() # ça marche mais pb avec la taille des barres --> voir comment faire et tricher
960
+ ex.fit_to_height()
961
+ ex.fit_to_width()
962
+
963
+ # ça marche pas mal et en plus c'est simple!!!
964
+ ex.fit_to_width_or_height()
965
+ ex.fit_to_width_or_height()
966
+ ex.fit_to_width_or_height()
967
+ ex.fit_to_width_or_height()
968
+
969
+ # img = Img('/E/Sample_images/sample_images_PA/mini10_fake_swaps/focused_Series012.png')
970
+ ex.set_image(img)
971
+ ex.clear()
972
+
973
+ ex.set_image(img, nb=0)
974
+ img = Img('/E/Sample_images/sample_images_PA/mini10_fake_swaps/focused_Series012.png')
975
+ ex.set_image(img, nb=3)
976
+
977
+ ex.scale_image_all(0.3)
978
+ ex.scaleImage(1, nb=3) # tt marche et en plus vraiment pas mal --> je vais adorer ce truc à la fin!!!
979
+
980
+ # ça a l'air de marcher --> just allow or disallow sync
981
+ # ex.set_image(None)
982
+ ex.show()
983
+ app.exec_()
984
+
985
+ # all of the things seem ok !!!
986
+
987
+ # all is ok for now
988
+ # maybe add ROIs to zoom on a region of the image
989
+ # maybe stor all in the image because it is easier to handle !!!