21
21
###############################################################################
22
22
import pytest
23
23
from PyQt5 .QtWidgets import QMainWindow
24
- from PyQt5 .QtCore import QPointF , Qt
24
+ from PyQt5 .QtCore import QPointF , Qt , QCoreApplication
25
25
from PyQt5 .QtGui import QColor
26
26
27
27
import numpy as np
28
28
import vigra
29
29
from ilastik .applets .layerViewer .layerViewerGui import LayerViewerGui
30
- from lazyflow .operators .opReorderAxes import OpReorderAxes
31
30
from volumina .volumeEditor import VolumeEditor
32
31
from volumina .volumeEditorWidget import VolumeEditorWidget
33
32
from volumina .layerstack import LayerStackModel
34
33
from volumina .pixelpipeline .datasources import LazyflowSource
35
- from volumina .layer import AlphaModulatedLayer
34
+ from volumina .layer import AlphaModulatedLayer , ColortableLayer , NormalizableLayer , RGBALayer
36
35
from lazyflow .graph import Operator , InputSlot , OutputSlot , Graph
37
36
37
+ # taken from https://sashat.me/2017/01/11/list-of-20-simple-distinct-colors/
38
+ default16_new = [
39
+ QColor (0 , 0 , 0 , 0 ).rgba (), # transparent
40
+ QColor (255 , 225 , 25 ).rgba (), # yellow
41
+ QColor (0 , 130 , 200 ).rgba (), # blue
42
+ QColor (230 , 25 , 75 ).rgba (), # red
43
+ QColor (70 , 240 , 240 ).rgba (), # cyan
44
+ QColor (60 , 180 , 75 ).rgba (), # green
45
+ QColor (250 , 190 , 190 ).rgba (), # pink
46
+ QColor (170 , 110 , 40 ).rgba (), # brown
47
+ QColor (145 , 30 , 180 ).rgba (), # purple
48
+ QColor (0 , 128 , 128 ).rgba (), # teal
49
+ QColor (245 , 130 , 48 ).rgba (), # orange
50
+ QColor (240 , 50 , 230 ).rgba (), # magenta
51
+ QColor (210 , 245 , 60 ).rgba (), # lime
52
+ QColor (255 , 215 , 180 ).rgba (), # coral
53
+ QColor (230 , 190 , 255 ).rgba (), # lavender
54
+ QColor (128 , 128 , 128 ).rgba (), # gray
55
+ ]
38
56
39
57
class MainWindow (QMainWindow ):
40
58
def __init__ (self ):
41
59
super ().__init__ ()
42
60
self .volumeEditorWidget = VolumeEditorWidget (parent = self )
43
61
44
62
45
- class OpTestImgaeSlots (Operator ):
63
+ class OpTestImageSlots (Operator ):
46
64
"""test operator, containing 3-dim test data"""
47
-
48
- GrayscaleImageIn = InputSlot ()
49
- Label1ImageIn = InputSlot ()
50
- Label2ImageIn = InputSlot ()
51
-
52
- GrayscaleImageOut = OutputSlot ()
53
- Label1ImageOut = OutputSlot ()
54
- Label2ImageOut = OutputSlot ()
65
+ GrayscaleIn = InputSlot ()
66
+ RgbaIn = InputSlot (level = 1 )
67
+ ColorTblIn1 = InputSlot ()
68
+ ColorTblIn2 = InputSlot ()
69
+ AlphaModulatedIn = InputSlot ()
70
+ Segmentation1In = InputSlot ()
71
+ Segmentation2In = InputSlot ()
72
+
73
+ GrayscaleOut = OutputSlot ()
74
+ RgbaOut = OutputSlot (level = 1 )
75
+ ColorTblOut1 = OutputSlot ()
76
+ ColorTblOut2 = OutputSlot ()
77
+ AlphaModulatedOut = OutputSlot ()
78
+ Segmentation1Out = OutputSlot ()
79
+ Segmentation2Out = OutputSlot ()
55
80
56
81
def __init__ (self , * args , ** kwargs ):
57
82
super ().__init__ (* args , ** kwargs )
58
83
59
- width , height , depth = 300 , 200 , 40
60
-
61
- # create 2-dimensional images
62
- grayscaleImageSource = np .random .randint (0 , 255 , (depth , height , width , 1 ))
63
- label1ImageSource = np .zeros ((depth , height , width , 3 ), dtype = np .int32 )
64
- label2ImageSource = np .zeros ((depth , height , width , 3 ), dtype = np .int32 )
65
-
66
- for z , set1 in enumerate (grayscaleImageSource [:, :, :, 0 ]):
67
- for y , set2 in enumerate (set1 ):
68
- for x , set3 in enumerate (set2 ):
69
- if z in range (5 , 20 ) and y in range (20 , 30 ) and x in range (80 , 140 ):
70
- label1ImageSource [z , y , x , :] = [255 , 255 , 255 ]
71
- if z in range (25 , 37 ) and y in range (100 , 150 ) and x in range (10 , 60 ):
72
- label2ImageSource [z , y , x , :] = [255 , 255 , 255 ]
73
-
74
- self .GrayscaleImageIn .setValue (grayscaleImageSource , notify = False , check_changed = False )
75
- self .Label1ImageIn .setValue (label1ImageSource , notify = False , check_changed = False )
76
- self .Label2ImageIn .setValue (label2ImageSource , notify = False , check_changed = False )
77
-
78
- self .GrayscaleImageIn .meta .axistags = vigra .defaultAxistags ("tzyxc" [5 - len (self .GrayscaleImageIn .meta .shape ):])
79
- self .Label1ImageIn .meta .axistags = vigra .defaultAxistags ("tzyxc" [5 - len (self .Label1ImageIn .meta .shape ):])
80
- self .Label2ImageIn .meta .axistags = vigra .defaultAxistags ("tzyxc" [5 - len (self .Label2ImageIn .meta .shape ):])
81
-
82
- self .GrayscaleImageOut .connect (self .GrayscaleImageIn )
83
- self .Label1ImageOut .connect (self .Label1ImageIn )
84
- self .Label2ImageOut .connect (self .Label2ImageIn )
84
+ time , width , height , depth = 4 , 300 , 200 , 10
85
+ self .dataShape = (time , width , height , depth , 1 )
86
+ shape4d = (time , width , height , depth , 1 )
87
+ shape5d1 = (4 , time , width , height , depth , 1 )
88
+ shape5d2 = (time , width , height , depth , 3 )
89
+
90
+ # create images
91
+ grayscaleImage = np .random .randint (0 , 255 , shape4d )
92
+ rgbaImage = np .random .randint (0 , 255 , shape5d1 )
93
+ colorTblImage1 = np .random .randint (0 , 10 , shape4d )
94
+ colorTblImage2 = np .random .randint (0 , 10 , shape4d )
95
+ AlphaModImage = np .zeros (shape5d2 , dtype = np .int32 )
96
+ Segment1Image = np .zeros (shape5d2 , dtype = np .int32 )
97
+ Segment2Image = np .zeros (shape5d2 , dtype = np .int32 )
98
+
99
+ # define some dummy segmentations
100
+ for t in range (time ):
101
+ for x in range (width ):
102
+ for y in range (height ):
103
+ for z in range (depth ):
104
+ if t == 3 and z in range (5 , 9 ) and y in range (20 , 30 ) and x in range (80 , 140 ):
105
+ Segment1Image [t , x , y , z , :] = [255 , 255 , 255 ]
106
+ AlphaModImage [t , x , y , z , :] = [255 , 255 , 255 ]
107
+ colorTblImage1 [t , x , y , z , :] = 0
108
+ if t == 1 and z in range (0 , 6 ) and y in range (100 , 150 ) and x in range (10 , 60 ):
109
+ Segment2Image [t , x , y , z , :] = [255 , 255 , 255 ]
110
+ colorTblImage2 [t , x , y , z , :] = 0
111
+
112
+ self .GrayscaleIn .setValue (grayscaleImage , notify = False , check_changed = False )
113
+ self .RgbaIn .setValues (rgbaImage )
114
+ self .ColorTblIn1 .setValue (colorTblImage1 , notify = False , check_changed = False )
115
+ self .ColorTblIn2 .setValue (colorTblImage2 , notify = False , check_changed = False )
116
+ self .AlphaModulatedIn .setValue (AlphaModImage , notify = False , check_changed = False )
117
+ self .Segmentation1In .setValue (Segment1Image , notify = False , check_changed = False )
118
+ self .Segmentation2In .setValue (Segment2Image , notify = False , check_changed = False )
119
+
120
+ atags3d = "txyzc" [5 - len (shape4d ):]
121
+ atags4d2 = "txyzc" [5 - len (shape5d2 ):]
122
+ self .GrayscaleIn .meta .axistags = vigra .defaultAxistags (atags3d )
123
+ for i in range (4 ):
124
+ self .RgbaIn [i ].meta .axistags = vigra .defaultAxistags (atags3d )
125
+ self .ColorTblIn1 .meta .axistags = vigra .defaultAxistags (atags3d )
126
+ self .ColorTblIn2 .meta .axistags = vigra .defaultAxistags (atags3d )
127
+ self .AlphaModulatedIn .meta .axistags = vigra .defaultAxistags (atags4d2 )
128
+ self .Segmentation1In .meta .axistags = vigra .defaultAxistags (atags4d2 )
129
+ self .Segmentation2In .meta .axistags = vigra .defaultAxistags (atags4d2 )
130
+
131
+ self .GrayscaleOut .connect (self .GrayscaleIn )
132
+ self .RgbaOut .connect (self .RgbaIn )
133
+ self .ColorTblOut1 .connect (self .ColorTblIn1 )
134
+ self .ColorTblOut2 .connect (self .ColorTblIn2 )
135
+ self .AlphaModulatedOut .connect (self .AlphaModulatedIn )
136
+ self .Segmentation1Out .connect (self .Segmentation1In )
137
+ self .Segmentation2Out .connect (self .Segmentation2In )
85
138
86
139
87
140
class TestSpinBoxImageView (object ):
@@ -98,42 +151,47 @@ def setupClass(self, qtbot):
98
151
self .layerStack = LayerStackModel ()
99
152
100
153
g = Graph ()
101
- self .op = OpTestImgaeSlots (graph = g )
102
-
103
- self .grayscaleLayer = LayerViewerGui ._create_grayscale_layer_from_slot (self .op .GrayscaleImageOut , 1 )
104
- self .labelLayer1 = AlphaModulatedLayer (LazyflowSource (self .op .Label1ImageOut ), tintColor = QColor (Qt .cyan ),
105
- range = (0 , 255 ), normalize = (0 , 255 ))
106
- self .labelLayer2 = AlphaModulatedLayer (LazyflowSource (self .op .Label2ImageOut ), tintColor = QColor (Qt .yellow ),
107
- range = (0 , 255 ), normalize = (0 , 255 ))
108
-
109
- self .labelLayer1 .name = "Segmentation (Label 1)"
110
- self .labelLayer2 .name = "Segmentation (Label 2)"
154
+ self .op = OpTestImageSlots (graph = g )
155
+
156
+ self .grayscaleLayer = LayerViewerGui ._create_grayscale_layer_from_slot (self .op .GrayscaleOut , 1 )
157
+ self .segLayer1 = AlphaModulatedLayer (LazyflowSource (self .op .Segmentation1Out ), tintColor = QColor (Qt .cyan ),
158
+ range = (0 , 255 ), normalize = (0 , 255 ))
159
+ self .segLayer2 = AlphaModulatedLayer (LazyflowSource (self .op .Segmentation2Out ), tintColor = QColor (Qt .yellow ),
160
+ range = (0 , 255 ), normalize = (0 , 255 ))
161
+ self .alphaModLayer = AlphaModulatedLayer (LazyflowSource (self .op .AlphaModulatedOut ),
162
+ tintColor = QColor (Qt .magenta ), range = (0 , 255 ), normalize = (0 , 255 ))
163
+ self .colorTblLayer1 = ColortableLayer (LazyflowSource (self .op .ColorTblOut1 ), default16_new )
164
+ self .colorTblLayer2 = ColortableLayer (LazyflowSource (self .op .ColorTblOut2 ), default16_new )
165
+ self .rgbaLayer = RGBALayer (red = LazyflowSource (self .op .RgbaOut [0 ]), green = LazyflowSource (self .op .RgbaOut [1 ]),
166
+ blue = LazyflowSource (self .op .RgbaOut [2 ]), alpha = LazyflowSource (self .op .RgbaOut [3 ]))
167
+ self .emptyRgbaLayer = RGBALayer ()
168
+
169
+ self .segLayer1 .name = "Segmentation (Label 1)"
170
+ self .segLayer2 .name = "Segmentation (Label 2)"
171
+ self .grayscaleLayer .name = "Raw Input"
172
+ self .colorTblLayer1 .name = "Labels"
173
+ self .colorTblLayer2 .name = "pos info in Normalizable"
174
+ self .rgbaLayer .name = "rgba layer"
175
+ self .emptyRgbaLayer .name = "empty rgba layer"
176
+ self .alphaModLayer .name = "alpha modulated layer"
111
177
112
178
self .layerStack .append (self .grayscaleLayer )
113
- self .layerStack .append (self .labelLayer1 )
114
- self .layerStack .append (self .labelLayer2 )
115
-
116
- activeOutSlot = self .op .GrayscaleImageOut # take any out slot here
117
- if activeOutSlot .ready () and activeOutSlot .meta .axistags is not None :
118
- # Use an OpReorderAxes adapter to transpose the shape for us.
119
- op5 = OpReorderAxes (graph = g )
120
- op5 .Input .connect (activeOutSlot )
121
- op5 .AxisOrder .setValue ('txyzc' )
122
- shape = op5 .Output .meta .shape
123
-
124
- # We just needed the op to determine the transposed shape.
125
- # Disconnect it so it can be garbage collected.
126
- op5 .Input .disconnect ()
127
- op5 .cleanUp ()
179
+ self .layerStack .append (self .segLayer1 )
180
+ self .layerStack .append (self .segLayer2 )
181
+ self .layerStack .append (self .colorTblLayer1 )
182
+ self .layerStack .append (self .colorTblLayer2 )
183
+ self .layerStack .append (self .rgbaLayer )
184
+ self .layerStack .append (self .emptyRgbaLayer )
185
+ self .layerStack .append (self .alphaModLayer )
128
186
129
187
self .editor = VolumeEditor (self .layerStack , self .main )
130
188
self .editorWidget = self .main .volumeEditorWidget
131
189
self .editorWidget .init (self .editor )
132
190
133
- self .editor .dataShape = shape
191
+ self .editor .dataShape = self . op . dataShape
134
192
135
- # Find the xyz midpoint
136
- midpos5d = [x // 2 for x in shape ]
193
+ # Find the xyz origin
194
+ midpos5d = [x // 2 for x in self . op . dataShape ]
137
195
# center viewer there
138
196
# set xyz position
139
197
midpos3d = midpos5d [1 :4 ]
@@ -143,18 +201,23 @@ def setupClass(self, qtbot):
143
201
self .editor .navCtrl .changeSliceAbsolute (midpos3d [i ], i )
144
202
145
203
self .main .setCentralWidget (self .editorWidget )
204
+ self .main .setFixedSize (1000 , 800 )
146
205
self .main .show ()
147
206
self .qtbot .addWidget (self .main )
148
207
149
208
def testAddingAndRemovingPosVal (self ):
150
209
assert 0 == len (self .editorWidget .quadViewStatusBar .layerValueWidgets )
151
210
152
211
for layer in self .layerStack :
212
+ layer .visible = True
153
213
if not layer .showPosValue :
154
214
layer .showPosValue = True
155
215
if not layer .visible :
156
216
layer .visible = True
157
217
218
+ for i in range (30 ):
219
+ QCoreApplication .processEvents ()
220
+
158
221
for layer in self .layerStack :
159
222
assert layer in self .editorWidget .quadViewStatusBar .layerValueWidgets
160
223
@@ -174,47 +237,85 @@ def testLayerPositionValueStrings(self):
174
237
if not layer .visible :
175
238
layer .visible = True
176
239
177
- x , y , z = 90 , 25 , 10
240
+ t , x , y , z = 3 , 90 , 25 , 6
241
+
242
+ grayValidationString = "Raw I.:" + str (self .op .GrayscaleIn .value [t , x , y , z , 0 ])
243
+ labelValidationString = "Label 1"
244
+ colorTbl1ValidationString = "-"
245
+ colorTbl2ValidationString = "pos i. i. N.:" + str (self .op .ColorTblOut2 .value [t , x , y , z , 0 ])
246
+ rgbaValidationString = "rgba l.:{};{};{};{}" .format (* [str (slot .value [t , x , y , z , 0 ]) for slot in self .op .RgbaIn ])
247
+ emptyRgbaValidationString = "empty r. l.:0;0;0;255"
248
+ alphaModValidationString = "alpha m. l.:" + str (self .op .AlphaModulatedOut .value [t , x , y , z , 0 ])
178
249
179
- posVal = 255 - int (self .op .GrayscaleImageIn .value [z , y , x , 0 ])
180
- grayValidationStrings = ["Gray:" + str (posVal ), "Gray:" + str (posVal + 1 ), "Gray:" + str (posVal - 1 )]
181
- label1ValidationString = "Label 1"
182
- label2ValidationString = "Label 2"
183
250
184
251
signal = self .editor .posModel .cursorPositionChanged
185
252
with self .qtbot .waitSignal (signal , timeout = 1000 ):
186
253
self .editor .navCtrl .changeSliceAbsolute (z , 2 )
254
+ self .editor .navCtrl .changeTime (t )
187
255
188
- # After change of crosshair positions tiles are marked dirty.
189
- self .updateAllTiles (self .editor .imageScenes ) # Wait for all tiles being refreshed
256
+ QCoreApplication .processEvents ()
257
+ QCoreApplication .processEvents ()
258
+ QCoreApplication .processEvents ()
259
+ QCoreApplication .processEvents ()
190
260
191
- signals = [self .editorWidget .quadViewStatusBar .layerValueWidgets [self .grayscaleLayer ].textChanged ,
192
- self .editorWidget .quadViewStatusBar .layerValueWidgets [self .labelLayer1 ].textChanged ]
193
- with self .qtbot .waitSignals (signals , timeout = 1000 ):
194
- self .editor .navCtrl .positionDataCursor (QPointF (x , y ), 2 )
195
261
196
- self .updateAllTiles ( self . editor .imageScenes ) # Wait for all tiles being refreshed
262
+ self .editor .navCtrl . positionDataCursor ( QPointF ( 0 , 0 ), 2 )
197
263
264
+ self .editor .navCtrl .positionDataCursor (QPointF (x , y ), 2 )
265
+
266
+ assert self .editorWidget .quadViewStatusBar .xSpinBox .value () == x
267
+ assert self .editorWidget .quadViewStatusBar .ySpinBox .value () == y
268
+ assert self .editorWidget .quadViewStatusBar .zSpinBox .value () == z
269
+ assert self .editorWidget .quadViewStatusBar .layerValueWidgets [
270
+ self .grayscaleLayer ].text () == grayValidationString
271
+ assert self .editorWidget .quadViewStatusBar .layerValueWidgets [
272
+ self .segLayer1 ].text () == labelValidationString
198
273
assert self .editorWidget .quadViewStatusBar .layerValueWidgets [
199
- self .grayscaleLayer ].text () in grayValidationStrings
200
- assert self .editorWidget .quadViewStatusBar .layerValueWidgets [self .labelLayer1 ].text () == label1ValidationString
274
+ self .segLayer2 ].text () == labelValidationString
275
+ assert self .editorWidget .quadViewStatusBar .layerValueWidgets [
276
+ self .colorTblLayer1 ].text () == colorTbl1ValidationString
277
+ assert self .editorWidget .quadViewStatusBar .layerValueWidgets [
278
+ self .colorTblLayer2 ].text () == colorTbl2ValidationString
279
+ assert self .editorWidget .quadViewStatusBar .layerValueWidgets [
280
+ self .rgbaLayer ].text () == rgbaValidationString
281
+ assert self .editorWidget .quadViewStatusBar .layerValueWidgets [
282
+ self .emptyRgbaLayer ].text () == emptyRgbaValidationString
283
+ assert self .editorWidget .quadViewStatusBar .layerValueWidgets [
284
+ self .alphaModLayer ].text () == alphaModValidationString
201
285
202
- x , y , z = 39 , 130 , 30
286
+ t , x , y , z = 1 , 39 , 130 , 3
203
287
204
- posVal = 255 - int (self .op .GrayscaleImageIn .value [z , y , x , 0 ])
205
- grayValidationStrings = ["Gray:" + str (posVal ), "Gray:" + str (posVal + 1 ), "Gray:" + str (posVal - 1 )]
288
+ grayValidationString = "Raw I.:" + str (self .op .GrayscaleIn .value [t , x , y , z , 0 ])
289
+ labelValidationString = "Label 2"
290
+ colorTbl1ValidationString = "Labels:" + str (self .op .ColorTblIn1 .value [t , x , y , z , 0 ])
291
+ colorTbl2ValidationString = "pos i. i. N.:" + str (self .op .ColorTblIn2 .value [t , x , y , z , 0 ])
292
+ rgbaValidationString = "rgba l.:{};{};{};{}" .format (* [str (slot .value [t , x , y , z , 0 ]) for slot in self .op .RgbaIn ])
293
+ emptyRgbaValidationString = "empty r. l.:0;0;0;255"
294
+ alphaModValidationString = "alpha m. l.:" + str (self .op .AlphaModulatedIn .value [t , x , y , z , 0 ])
206
295
207
296
with self .qtbot .waitSignal (signal , timeout = 1000 ):
208
297
self .editor .navCtrl .changeSliceAbsolute (y , 1 )
298
+ self .editor .navCtrl .changeTime (t )
209
299
210
- self .updateAllTiles (self .editor .imageScenes ) # Wait for all tiles being refreshed
211
-
212
- with self .qtbot .waitSignals (signals , timeout = 1000 ):
213
- self .editor .navCtrl .positionDataCursor (QPointF (x , z ), 1 )
214
-
215
- self .updateAllTiles (self .editor .imageScenes ) # Wait for all tiles being refreshed
300
+ self .editor .navCtrl .positionDataCursor (QPointF (x , z ), 1 )
216
301
302
+ assert self .editorWidget .quadViewStatusBar .xSpinBox .value () == x
303
+ assert self .editorWidget .quadViewStatusBar .ySpinBox .value () == y
304
+ assert self .editorWidget .quadViewStatusBar .zSpinBox .value () == z
305
+ assert self .editorWidget .quadViewStatusBar .layerValueWidgets [
306
+ self .grayscaleLayer ].text () == grayValidationString
307
+ assert self .editorWidget .quadViewStatusBar .layerValueWidgets [
308
+ self .segLayer1 ].text () == labelValidationString
309
+ assert self .editorWidget .quadViewStatusBar .layerValueWidgets [
310
+ self .segLayer2 ].text () == labelValidationString
311
+ assert self .editorWidget .quadViewStatusBar .layerValueWidgets [
312
+ self .colorTblLayer1 ].text () == colorTbl1ValidationString
313
+ assert self .editorWidget .quadViewStatusBar .layerValueWidgets [
314
+ self .colorTblLayer2 ].text () == colorTbl2ValidationString
315
+ assert self .editorWidget .quadViewStatusBar .layerValueWidgets [
316
+ self .rgbaLayer ].text () == rgbaValidationString
317
+ assert self .editorWidget .quadViewStatusBar .layerValueWidgets [
318
+ self .emptyRgbaLayer ].text () == emptyRgbaValidationString
217
319
assert self .editorWidget .quadViewStatusBar .layerValueWidgets [
218
- self .grayscaleLayer ].text () in grayValidationStrings
219
- assert self .editorWidget .quadViewStatusBar .layerValueWidgets [self .labelLayer2 ].text () == label2ValidationString
320
+ self .alphaModLayer ].text () == alphaModValidationString
220
321
0 commit comments