コード例 #1
0
    def testNonEmptyLayerStackModel(self):
        lsm = LayerStackModel()

        lsm.append(self.layer1)
        lsm.append(self.layer2)
        lsm.append(self.layer3)

        ip = ImagePump(lsm, SliceProjection())
        self.assertEqual(len(lsm), 3)
        self.assertEqual(len(ip.stackedImageSources), 3)
        self.assertEqual(len(ip.syncedSliceSources), 3)

        self.assertEqual(len(ip.stackedImageSources.getRegisteredLayers()), 3)
        for layer in lsm:
            self.assertTrue(ip.stackedImageSources.isRegistered(layer))

        lsm.deleteSelected()
        self.assertEqual(len(lsm), 2)
        self.assertEqual(len(ip.stackedImageSources), 2)
        self.assertEqual(len(ip.syncedSliceSources), 2)
        self.assertEqual(len(ip.stackedImageSources.getRegisteredLayers()), 2)
        for layer in lsm:
            self.assertTrue(ip.stackedImageSources.isRegistered(layer))

        lsm.clear()
        self.assertEqual(len(lsm), 0)
        self.assertEqual(len(ip.stackedImageSources), 0)
        self.assertEqual(len(ip.syncedSliceSources), 0)
        self.assertEqual(len(ip.stackedImageSources.getRegisteredLayers()), 0)
コード例 #2
0
    def test_repaint_after_visible_change(self):
        self.model = LayerStackModel()

        self.o1 = Layer([])
        self.o1.name = "Fancy Layer"
        self.o1.opacity = 0.5
        self.model.append(self.o1)

        self.o2 = Layer([])
        self.o2.name = "Some other Layer"
        self.o2.opacity = 0.25
        self.model.append(self.o2)

        self.view = LayerWidget(None, self.model)
        self.view.show()
        self.view.updateGeometry()

        self.w = QWidget()
        self.lh = QHBoxLayout(self.w)
        self.lh.addWidget(self.view)
        self.w.setGeometry(100, 100, 300, 300)
        self.w.show()
        self.w.raise_()

        # Run the test within the GUI event loop
        QTimer.singleShot(500, self.impl)
        self.app.exec_()

        # Were there errors?
        assert not TestLayerWidget.errors, "There were GUI errors/failures.  See above."
コード例 #3
0
ファイル: viewer.py プロジェクト: christophdecker/volumina
 def initLayerstackModel(self):
     self.layerstack = LayerStackModel()
     self.layerWidget.init(self.layerstack)
     model = self.layerstack
     self.UpButton.clicked.connect(model.moveSelectedUp)
     model.canMoveSelectedUp.connect(self.UpButton.setEnabled)
     self.DownButton.clicked.connect(model.moveSelectedDown)
     model.canMoveSelectedDown.connect(self.DownButton.setEnabled)
     self.DeleteButton.clicked.connect(model.deleteSelected)
     model.canDeleteSelected.connect(self.DeleteButton.setEnabled)
コード例 #4
0
ファイル: imagepump_tests.py プロジェクト: JensNRAD/volumina
    def testNonEmptyLayerStackModel( self ):
        lsm = LayerStackModel()
        
        lsm.append(self.layer1)
        lsm.append(self.layer2)
        lsm.append(self.layer3)
        
        ip = ImagePump( lsm, SliceProjection() )
        self.assertEqual( len(lsm), 3 )
        self.assertEqual( len(ip.stackedImageSources), 3 )
        self.assertEqual( len(ip.syncedSliceSources), 3 )
        
        self.assertEqual( len(ip.stackedImageSources.getRegisteredLayers()), 3 )
        for layer in lsm:
            self.assertTrue( ip.stackedImageSources.isRegistered(layer) )

        lsm.deleteSelected()
        self.assertEqual( len(lsm), 2 )
        self.assertEqual( len(ip.stackedImageSources), 2 )
        self.assertEqual( len(ip.syncedSliceSources), 2 )
        self.assertEqual( len(ip.stackedImageSources.getRegisteredLayers()), 2 )
        for layer in lsm:
            self.assertTrue( ip.stackedImageSources.isRegistered(layer) )

        lsm.clear()
        self.assertEqual( len(lsm), 0 )
        self.assertEqual( len(ip.stackedImageSources), 0 )
        self.assertEqual( len(ip.syncedSliceSources), 0 )
        self.assertEqual( len(ip.stackedImageSources.getRegisteredLayers()), 0 )
コード例 #5
0
ファイル: lazy_test.py プロジェクト: Tomaz-Vieira/volumina
    class ImageScene2D_LazyTest(ut.TestCase):
        def setUp(self):
            self.layerstack = LayerStackModel()
            self.sims = StackedImageSources(self.layerstack)

            self.g = Graph()
            self.op = OpLazy(self.g)
            self.ds = LazyflowSource(self.op.Output)

            self.ss = SliceSource(self.ds, projectionAlongTZC)

            self.layer = GrayscaleLayer(self.ds, normalize=False)
            self.layerstack.append(self.layer)
            self.ims = imsfac.createImageSource(self.layer, [self.ss])
            self.sims.register(self.layer, self.ims)

            self.scene = ImageScene2D(PositionModel(), (0, 0, 0), preemptive_fetch_number=0)
            self.scene.setCacheSize(1)

            self.scene.stackedImageSources = self.sims
            self.scene.dataShape = (30, 30)

        def renderScene(self, s, exportFilename=None, joinRendering=True):
            img = QImage(30, 30, QImage.Format_ARGB32_Premultiplied)
            img.fill(Qt.white)
            p = QPainter(img)

            s.render(p)  # trigger a rendering of the whole scene
            if joinRendering:
                # wait for all the data to arrive
                s.joinRenderingAllTiles(viewport_only=False)  # There is no viewport!
                # finally, render everything
                s.render(p)
            p.end()

            if exportFilename is not None:
                img.save(exportFilename)
            return byte_view(img)

        def testLazy(self):
            for i in range(3):
                self.op.setConstant(i)
                aimg = self.renderScene(self.scene, "/tmp/a_%03d.png" % i)
                assert numpy.all(aimg[:, :, 0] == i), "!= %d, [0,0,0]=%d" % (i, aimg[0, 0, 0])

                self.op.setConstant(42)
                self.op.setDelay(1)
                aimg = self.renderScene(self.scene, joinRendering=False, exportFilename="/tmp/x_%03d.png" % i)
                # this should be "i", not 255 (the default background for the imagescene)
                assert numpy.all(aimg[:, :, 0] == i), "!= %d, [0,0,0]=%d" % (i, aimg[0, 0, 0])

                # Now give the scene time to update before we change it again...
                self.scene.joinRenderingAllTiles(viewport_only=False)
コード例 #6
0
    def testRegisterAndDeregister(self):
        lsm = LayerStackModel()
        sims = StackedImageSources(lsm)
        self.assertEqual(len(lsm), 0)
        self.assertEqual(len(sims), 0)

        lsm.append(self.layer1)
        lsm.append(self.layer2)
        lsm.append(self.layer3)
        self.assertEqual(lsm.layerIndex(self.layer1), 2)
        self.assertEqual(lsm.layerIndex(self.layer2), 1)
        self.assertEqual(lsm.layerIndex(self.layer3), 0)
        self.assertEqual(len(lsm), 3)
        self.assertEqual(len(sims), 0)

        self.assertFalse(sims.isRegistered(self.layer2))
        sims.register(self.layer2, self.ims2)
        self.assertTrue(sims.isRegistered(self.layer2))
        self.assertEqual(len(sims), 1)
        self.assertEqual(sims.getImageSource(0), self.ims2)

        sims.register(self.layer1, self.ims1)
        sims.register(self.layer3, self.ims3)
        sims.deregister(self.layer2)
        self.assertTrue(sims.isRegistered(self.layer1))
        self.assertFalse(sims.isRegistered(self.layer2))
        self.assertTrue(sims.isRegistered(self.layer3))
        self.assertEqual(len(lsm), 3)
        self.assertEqual(len(sims), 2)
        self.assertEqual(sims.getImageSource(0), self.ims3)
        self.assertEqual(sims.getImageSource(1), self.ims1)

        for i, v in enumerate(sims):
            if i == 0:
                self.assertEqual(len(v), 3)
                self.assertEqual(v[0], self.layer3.visible)
                self.assertEqual(v[1], self.layer3.opacity)
                self.assertEqual(v[2], self.ims3)
            elif i == 1:
                self.assertEqual(len(v), 3)
                self.assertEqual(v[0], self.layer1.visible)
                self.assertEqual(v[1], self.layer1.opacity)
                self.assertEqual(v[2], self.ims1)
            else:
                raise Exception("unexpected index")

        sims.deregister(self.layer1)
        sims.deregister(self.layer3)
        self.assertEqual(len(lsm), 3)
        self.assertEqual(len(sims), 0)

        lsm.clear()
コード例 #7
0
    def createWidget(self, parent):
        a = (numpy.random.random((1, 100, 200, 300, 1)) * 255).astype(numpy.uint8)
        source = ArraySource(a)
        layerstack = LayerStackModel()
        layerstack.append(GrayscaleLayer(source))

        editor = VolumeEditor(layerstack, labelsink=None, parent=self)
        widget = VolumeEditorWidget(parent=parent)
        if not _has_lazyflow:
            widget.setEnabled(False)
        widget.init(editor)
        editor.dataShape = a.shape
        return widget
コード例 #8
0
    def createWidget(self, parent):
        a = (numpy.random.random((1,100,200,300,1))*255).astype(numpy.uint8)
        source = ArraySource(a)
        layerstack = LayerStackModel()
        layerstack.append( GrayscaleLayer( source ) )

        editor = VolumeEditor(layerstack, labelsink=None, parent=self)  
        widget = VolumeEditorWidget(parent=parent)
        if not _has_lazyflow:
            widget.setEnabled(False)
        widget.init(editor)
        editor.dataShape = a.shape
        return widget
コード例 #9
0
class Main(QMainWindow):
    def __init__(self, useGL, argv):
        QMainWindow.__init__(self)
        self.initUic()

    def initUic(self):

        self.g = g = Graph()

        #get the absolute path of the 'ilastik' module
        uic.loadUi("designerElements/MainWindow.ui", self)

        self.actionQuit.triggered.connect(qApp.quit)

        def toggleDebugPatches(show):
            self.editor.showDebugPatches = show

        self.actionShowDebugPatches.toggled.connect(toggleDebugPatches)

        self.layerstack = LayerStackModel()

        readerNew = op.OpH5ReaderBigDataset(g)
        readerNew.inputs["Filenames"].setValue([
            "scripts/CB_compressed_XY.h5", "scripts/CB_compressed_XZ.h5",
            "scripts/CB_compressed_YZ.h5"
        ])
        readerNew.inputs["hdf5Path"].setValue("volume/data")

        datasrc = LazyflowSource(readerNew.outputs["Output"])

        layer1 = GrayscaleLayer(datasrc)
        layer1.name = "Big Data"

        self.layerstack.append(layer1)

        shape = readerNew.outputs["Output"].meta.shape
        print shape
        self.editor = VolumeEditor(shape, self.layerstack)
        #self.editor.setDrawingEnabled(False)

        self.volumeEditorWidget.init(self.editor)
        model = self.editor.layerStack
        self.layerWidget.init(model)

        self.UpButton.clicked.connect(model.moveSelectedUp)
        model.canMoveSelectedUp.connect(self.UpButton.setEnabled)
        self.DownButton.clicked.connect(model.moveSelectedDown)
        model.canMoveSelectedDown.connect(self.DownButton.setEnabled)
        self.DeleteButton.clicked.connect(model.deleteSelected)
        model.canDeleteSelected.connect(self.DeleteButton.setEnabled)
コード例 #10
0
ファイル: tiling_tests.py プロジェクト: skarale25/volumina
    def setUp( self ):
        dataShape = (1, 900, 400, 10, 1) # t,x,y,z,c
        data = np.indices(dataShape)[3].astype(np.uint8) # Data is labeled according to z-index
        self.ds1 = ArraySource( data )
        self.CONSTANT = 13
        self.ds2 = ConstantSource( self.CONSTANT )

        self.layer1 = GrayscaleLayer( self.ds1, normalize=False )
        self.layer1.visible = True
        self.layer1.opacity = 1.0

        self.layer2 = GrayscaleLayer( self.ds2, normalize=False )

        self.lsm = LayerStackModel()
        self.pump = ImagePump( self.lsm, SliceProjection(), sync_along=(0,1,2) )
コード例 #11
0
class ImageScene2DTest( ut.TestCase ):
    def setUp( self ):
        self.app = QApplication([], False)

        self.layerstack = LayerStackModel()
        self.sims = StackedImageSources( self.layerstack )

        self.GRAY = 201
        self.ds = ConstantSource(self.GRAY)
        self.layer = GrayscaleLayer( self.ds )
        self.layerstack.append(self.layer)
        self.ims = imsfac.createImageSource( self.layer, [self.ds] )
        self.sims.register(self.layer, self.ims)
        
        self.scene = ImageScene2D(self.app) 
        self.scene.stackedImageSources = self.sims
        self.scene.sceneShape = (310,290)

    def renderScene( self, s):
        img = QImage(310,290,QImage.Format_ARGB32_Premultiplied)
        p = QPainter(img)
        s.render(p)
        s.joinRendering()
        s.render(p)
        p.end()
        return byte_view(img)

    def testBasicImageRenderingCapability( self ):
        import time
        aimg = self.renderScene(self.scene)
        self.assertTrue(np.all(aimg[:,:,0:3] == self.GRAY))
        self.assertTrue(np.all(aimg[:,:,3] == 255))

    @ut.skipIf(os.getenv('TRAVIS'), 'fails on TRAVIS CI due to unknown reasons')
    def testToggleVisibilityOfOneLayer( self ):
        aimg = self.renderScene(self.scene)
        self.assertTrue(np.all(aimg[:,:,0:3] == self.GRAY))
        self.assertTrue(np.all(aimg[:,:,3] == 255))

        self.layer.visible = False
        aimg = self.renderScene(self.scene)
        self.assertTrue(np.all(aimg[:,:,0:3] == 255)) # all white
        self.assertTrue(np.all(aimg[:,:,3] == 255))

        self.layer.visible = True
        aimg = self.renderScene(self.scene)
        self.assertTrue(np.all(aimg[:,:,0:3] == self.GRAY))
        self.assertTrue(np.all(aimg[:,:,3] == 255))
コード例 #12
0
ファイル: layerwidget_test.py プロジェクト: JensNRAD/volumina
    def test_repaint_after_visible_change(self):
        self.model = LayerStackModel()

        self.o1 = Layer([])
        self.o1.name = "Fancy Layer"
        self.o1.opacity = 0.5
        self.model.append(self.o1)
        
        self.o2 = Layer([])
        self.o2.name = "Some other Layer"
        self.o2.opacity = 0.25
        self.model.append(self.o2)
        
        self.view = LayerWidget(None, self.model)
        self.view.show()
        self.view.updateGeometry()
    
        self.w = QWidget()
        self.lh = QHBoxLayout(self.w)
        self.lh.addWidget(self.view)
        self.w.setGeometry(100, 100, 300, 300)
        self.w.show()

        # Run the test within the GUI event loop
        QTimer.singleShot(500, self.impl )
        self.app.exec_()
        
        # Were there errors?
        assert not TestLayerWidget.errors, "There were GUI errors/failures.  See above."        
コード例 #13
0
    def testStackedImageSourcesProperty(self):
        s = ImageScene2D(PositionModel(), (0, 3, 4), preemptive_fetch_number=0)
        self.assertEqual(len(s.stackedImageSources), 0)

        sims = StackedImageSources(LayerStackModel())
        s.stackedImageSources = sims
        self.assertEqual(id(s.stackedImageSources), id(sims))
コード例 #14
0
    def setUp(self):
        self.layerstack = LayerStackModel()
        self.sims = StackedImageSources(self.layerstack)

        self.GRAY = 201
        self.ds = ConstantSource(self.GRAY)
        self.layer = GrayscaleLayer(self.ds)
        self.layerstack.append(self.layer)
        self.ims = imsfac.createImageSource(self.layer, [self.ds])
        self.sims.register(self.layer, self.ims)

        self.scene = ImageScene2D(PositionModel(), (0, 3, 4),
                                  preemptive_fetch_number=0)

        self.scene.stackedImageSources = self.sims
        self.scene.dataShape = (310, 290)
コード例 #15
0
ファイル: imagepump_tests.py プロジェクト: JensNRAD/volumina
    def testRegisterAndDeregister( self ):
        lsm = LayerStackModel()
        sims = StackedImageSources( lsm )
        self.assertEqual( len(lsm), 0 )
        self.assertEqual( len(sims), 0 )

        lsm.append(self.layer1)
        lsm.append(self.layer2)
        lsm.append(self.layer3)
        self.assertEqual( lsm.layerIndex(self.layer1), 2 )
        self.assertEqual( lsm.layerIndex(self.layer2), 1 )
        self.assertEqual( lsm.layerIndex(self.layer3), 0 )
        self.assertEqual( len(lsm), 3 )
        self.assertEqual( len(sims), 0 )

        self.assertFalse(sims.isRegistered(self.layer2))
        sims.register( self.layer2, self.ims2 )
        self.assertTrue(sims.isRegistered(self.layer2))
        self.assertEqual( len(sims), 1 )
        self.assertEqual( sims.getImageSource(0), self.ims2 )

        sims.register( self.layer1, self.ims1 )
        sims.register( self.layer3, self.ims3 )
        sims.deregister( self.layer2 )
        self.assertTrue( sims.isRegistered( self.layer1 ))
        self.assertFalse( sims.isRegistered( self.layer2 ))
        self.assertTrue( sims.isRegistered( self.layer3 ))
        self.assertEqual( len(lsm), 3 )
        self.assertEqual( len(sims), 2 )
        self.assertEqual( sims.getImageSource(0), self.ims3 )    
        self.assertEqual( sims.getImageSource(1), self.ims1 )

        for i,v in enumerate(sims):
            if i == 0:
                self.assertEqual(len(v), 3)
                self.assertEqual(v[0], self.layer3.visible) 
                self.assertEqual(v[1], self.layer3.opacity)
                self.assertEqual(v[2], self.ims3)  
            elif i == 1:
                self.assertEqual(len(v), 3)
                self.assertEqual(v[0], self.layer1.visible) 
                self.assertEqual(v[1], self.layer1.opacity)
                self.assertEqual(v[2], self.ims1)
            else:
                raise Exception("unexpected index")

        sims.deregister( self.layer1 )
        sims.deregister( self.layer3 )
        self.assertEqual( len(lsm), 3 )
        self.assertEqual( len(sims), 0 )

        lsm.clear()
コード例 #16
0
    def __init__(self,
                 posModel,
                 along,
                 preemptive_fetch_number=5,
                 parent=None,
                 name="Unnamed Scene",
                 swapped_default=False):
        """
        * preemptive_fetch_number -- number of prefetched slices; 0 turns the feature off
        * swapped_default -- whether axes should be swapped by default.

        """
        QGraphicsScene.__init__(self, parent=parent)

        self._along = along
        self._posModel = posModel

        # QGraphicsItems can change this if they are in a state that should temporarily forbid brushing
        # (For example, when the slice intersection marker is in 'draggable' state.)
        self.allow_brushing = True

        self._dataShape = (0, 0)
        self._dataRectItem = None  #A QGraphicsRectItem (or None)
        self._offsetX = 0
        self._offsetY = 0
        self.name = name

        self._stackedImageSources = StackedImageSources(LayerStackModel())
        self._showTileOutlines = False

        # FIXME: We don't show the red 'progress pies' because they look terrible.
        #        If we could fix their timing, maybe it would be worth it.
        self._showTileProgress = False

        self._tileProvider = None
        self._dirtyIndicator = None
        self._prefetching_enabled = False

        self._swappedDefault = swapped_default
        self.reset()

        # BowWave preemptive caching
        self.setPreemptiveFetchNumber(preemptive_fetch_number)
        self._course = (1, 1)  # (along, pos or neg direction)
        self._time = self._posModel.time
        self._channel = self._posModel.channel
        self._posModel.timeChanged.connect(self._onTimeChanged)
        self._posModel.channelChanged.connect(self._onChannelChanged)
        self._posModel.slicingPositionChanged.connect(
            self._onSlicingPositionChanged)

        self._allTilesCompleteEvent = threading.Event()
        self.dirty = False

        # We manually keep track of the tile-wise QGraphicsItems that
        # we've added to the scene in this dict, otherwise we would need
        # to use O(N) lookups for every tile by calling QGraphicsScene.items()
        self.tile_graphicsitems = defaultdict(
            set)  # [Tile.id] -> set(QGraphicsItems)
コード例 #17
0
class Main(QMainWindow):
     def __init__(self, useGL, argv):
         QMainWindow.__init__(self)
         self.initUic()
         
     def initUic(self):
         
        self.g=g=Graph() 
         
        #get the absolute path of the 'ilastik' module
        uic.loadUi("designerElements/MainWindow.ui", self) 
        
        self.actionQuit.triggered.connect(qApp.quit)
        def toggleDebugPatches(show):
            self.editor.showDebugPatches = show
        self.actionShowDebugPatches.toggled.connect(toggleDebugPatches)
        
        self.layerstack = LayerStackModel()
        
        readerNew=op.OpH5ReaderBigDataset(g)
        readerNew.inputs["Filenames"].setValue(["scripts/CB_compressed_XY.h5","scripts/CB_compressed_XZ.h5","scripts/CB_compressed_YZ.h5"])
        readerNew.inputs["hdf5Path"].setValue("volume/data")
        
        datasrc = LazyflowSource(readerNew.outputs["Output"])
        
        layer1 = GrayscaleLayer( datasrc )
        layer1.name = "Big Data"
        
        
        self.layerstack.append(layer1)
        
        shape=readerNew.outputs["Output"].meta.shape
        print shape
        self.editor = VolumeEditor(shape, self.layerstack)  
        #self.editor.setDrawingEnabled(False)
        
        self.volumeEditorWidget.init(self.editor)
        model = self.editor.layerStack
        self.layerWidget.init(model)
        
        self.UpButton.clicked.connect(model.moveSelectedUp)
        model.canMoveSelectedUp.connect(self.UpButton.setEnabled)
        self.DownButton.clicked.connect(model.moveSelectedDown)
        model.canMoveSelectedDown.connect(self.DownButton.setEnabled)
        self.DeleteButton.clicked.connect(model.deleteSelected)
        model.canDeleteSelected.connect(self.DeleteButton.setEnabled)        
コード例 #18
0
ファイル: viewer.py プロジェクト: jakirkham/volumina
 def initLayerstackModel(self):
     self.layerstack = LayerStackModel()
     self.layerWidget.init(self.layerstack)
     model = self.layerstack
     self.UpButton.clicked.connect(model.moveSelectedUp)
     model.canMoveSelectedUp.connect(self.UpButton.setEnabled)
     self.DownButton.clicked.connect(model.moveSelectedDown)
     model.canMoveSelectedDown.connect(self.DownButton.setEnabled)
     self.DeleteButton.clicked.connect(model.deleteSelected)
     model.canDeleteSelected.connect(self.DeleteButton.setEnabled)
コード例 #19
0
ファイル: lazy_test.py プロジェクト: Tomaz-Vieira/volumina
        def setUp(self):
            self.layerstack = LayerStackModel()
            self.sims = StackedImageSources(self.layerstack)

            self.g = Graph()
            self.op = OpLazy(self.g)
            self.ds = LazyflowSource(self.op.Output)

            self.ss = SliceSource(self.ds, projectionAlongTZC)

            self.layer = GrayscaleLayer(self.ds, normalize=False)
            self.layerstack.append(self.layer)
            self.ims = imsfac.createImageSource(self.layer, [self.ss])
            self.sims.register(self.layer, self.ims)

            self.scene = ImageScene2D(PositionModel(), (0, 0, 0), preemptive_fetch_number=0)
            self.scene.setCacheSize(1)

            self.scene.stackedImageSources = self.sims
            self.scene.dataShape = (30, 30)
コード例 #20
0
ファイル: tiling_tests.py プロジェクト: skarale25/volumina
    def setUp( self ):
        self.GRAY1 = 60
        self.ds1 = ConstantSource( self.GRAY1 )

        self.GRAY2 = 120
        self.ds2 = ConstantSource( self.GRAY2 )

        self.GRAY3 = 190
        self.ds3 = ConstantSource( self.GRAY3 )

        self.layer1 = GrayscaleLayer( self.ds1, normalize = False )
        self.layer1.visible = False
        self.layer1.opacity = 0.1
        self.ims1 = GrayscaleImageSource( self.ds1, self.layer1 )
        self.layer2 = GrayscaleLayer( self.ds2, normalize = False )
        self.layer2.visible = True
        self.layer2.opacity = 0.3
        self.ims2 = GrayscaleImageSource( self.ds2, self.layer2 )
        self.layer3 = GrayscaleLayer( self.ds3, normalize = False )
        self.layer3.visible = True
        self.layer3.opacity = 1.0
        self.ims3 = GrayscaleImageSource( self.ds3, self.layer3 )

        lsm = LayerStackModel()
        lsm.append(self.layer1)
        lsm.append(self.layer2)
        lsm.append(self.layer3)
        self.lsm = lsm
        sims = StackedImageSources( lsm )
        sims.register( self.layer1, self.ims1 )
        sims.register( self.layer2, self.ims2 )
        sims.register( self.layer3, self.ims3 )
        self.sims = sims
コード例 #21
0
ファイル: tiling_tests.py プロジェクト: LimpingTwerp/volumina
    def setUp( self ):
        dataShape = (1, 900, 400, 10, 1) # t,x,y,z,c
        data = np.indices(dataShape)[3] # Data is labeled according to z-index
        self.ds1 = ArraySource( data )
        self.CONSTANT = 13
        self.ds2 = ConstantSource( self.CONSTANT )

        self.layer1 = GrayscaleLayer( self.ds1 )
        self.layer1.visible = True
        self.layer1.opacity = 1.0

        self.layer2 = GrayscaleLayer( self.ds2 )

        self.lsm = LayerStackModel()
        self.pump = ImagePump( self.lsm, SliceProjection() )
コード例 #22
0
    def setUp( self ):
        self.layerstack = LayerStackModel()
        self.sims = StackedImageSources( self.layerstack )

        self.GRAY = 201
        self.ds = ConstantSource(self.GRAY)
        self.layer = GrayscaleLayer( self.ds )
        self.layerstack.append(self.layer)
        self.ims = imsfac.createImageSource( self.layer, [self.ds] )
        self.sims.register(self.layer, self.ims)

        self.scene = ImageScene2D(PositionModel(), (0,3,4), preemptive_fetch_number=0)

        self.scene.stackedImageSources = self.sims
        self.scene.dataShape = (310,290)
コード例 #23
0
    def setUp( self ):
        self.app = QApplication([], False)

        self.layerstack = LayerStackModel()
        self.sims = StackedImageSources( self.layerstack )

        self.GRAY = 201
        self.ds = ConstantSource(self.GRAY)
        self.layer = GrayscaleLayer( self.ds )
        self.layerstack.append(self.layer)
        self.ims = imsfac.createImageSource( self.layer, [self.ds] )
        self.sims.register(self.layer, self.ims)
        
        self.scene = ImageScene2D(self.app) 
        self.scene.stackedImageSources = self.sims
        self.scene.sceneShape = (310,290)
コード例 #24
0
ファイル: imageScene2D.py プロジェクト: burcin/volumina
    def __init__(self,
                 posModel,
                 along,
                 preemptive_fetch_number=5,
                 parent=None,
                 name="Unnamed Scene",
                 swapped_default=False):
        """
        * preemptive_fetch_number -- number of prefetched slices; 0 turns the feature off
        * swapped_default -- whether axes should be swapped by default.

        """
        QGraphicsScene.__init__(self, parent=parent)

        self._along = along
        self._posModel = posModel

        self._dataShape = (0, 0)
        self._dataRect = None  #A QGraphicsRectItem (or None)
        self._offsetX = 0
        self._offsetY = 0
        self.name = name

        self._stackedImageSources = StackedImageSources(LayerStackModel())
        self._showTileOutlines = False
        self._showTileProgress = True

        self._tileProvider = None
        self._dirtyIndicator = None
        self._prefetching_enabled = False

        self._swappedDefault = swapped_default
        self.reset()

        # BowWave preemptive caching
        self.setPreemptiveFetchNumber(preemptive_fetch_number)
        self._course = (1, 1)  # (along, pos or neg direction)
        self._time = self._posModel.time
        self._channel = self._posModel.channel
        self._posModel.timeChanged.connect(self._onTimeChanged)
        self._posModel.channelChanged.connect(self._onChannelChanged)
        self._posModel.slicingPositionChanged.connect(
            self._onSlicingPositionChanged)

        self._allTilesCompleteEvent = threading.Event()
コード例 #25
0
ファイル: lazy_test.py プロジェクト: JensNRAD/volumina
        def setUp( self ):
            self.layerstack = LayerStackModel()
            self.sims = StackedImageSources( self.layerstack )

            self.g = Graph()
            self.op = OpLazy(self.g)
            self.ds = LazyflowSource( self.op.Output )

            self.ss = SliceSource( self.ds, projectionAlongTZC )

            self.layer = GrayscaleLayer(self.ds, normalize = False)
            self.layerstack.append(self.layer)
            self.ims = imsfac.createImageSource( self.layer, [self.ss] )
            self.sims.register(self.layer, self.ims)

            self.scene = ImageScene2D(PositionModel(), (0,0,0), preemptive_fetch_number=0)
            self.scene.setCacheSize(1)

            self.scene.stackedImageSources = self.sims
            self.scene.dataShape = (30,30)
コード例 #26
0
ファイル: layerstack_test.py プロジェクト: JensNRAD/volumina
    def testAddingAndRemoving( self ):
        lsm = LayerStackModel()
        self.assertEqual(len(lsm), 0)

        lsm.append(self.l1)
        self.assertEqual(len(lsm), 1)
        self.assertEqual(lsm[0].name, self.l1.name )

        lsm.append(self.l2)
        self.assertEqual(len(lsm), 2)
        self.assertEqual(lsm[0].name, self.l2.name )
        self.assertEqual(lsm[1].name, self.l1.name )

        lsm.insert(1, self.l3)
        self.assertEqual(len(lsm), 3)
        self.assertEqual(lsm[0].name, self.l2.name )
        self.assertEqual(lsm[1].name, self.l3.name )
        self.assertEqual(lsm[2].name, self.l1.name )

        lsm.selectRow( 0 )
        lsm.deleteSelected()
        self.assertEqual(len(lsm), 2)
        self.assertEqual(lsm[0].name, self.l3.name )
        self.assertEqual(lsm[1].name, self.l1.name )

        lsm.clear()
        self.assertEqual(len(lsm), 0)
コード例 #27
0
ファイル: layerstack_test.py プロジェクト: JensNRAD/volumina
    def testMovingLayers( self ):
        lsm = LayerStackModel()
        lsm.append(self.l1)
        lsm.append(self.l2)
        lsm.append(self.l3)
        lsm.selectRow(1)
        self.assertEqual(len(lsm),3)
        self.assertEqual(lsm[0].name, self.l3.name )
        self.assertEqual(lsm[1].name, self.l2.name )
        self.assertEqual(lsm[2].name, self.l1.name )
        self.assertEqual(lsm.selectedRow(), 1)

        lsm.moveSelectedDown()
        self.assertEqual(lsm.selectedRow(), 2)
        self.assertEqual(len(lsm),3)
        self.assertEqual(lsm[0].name, self.l3.name )
        self.assertEqual(lsm[1].name, self.l1.name )
        self.assertEqual(lsm[2].name, self.l2.name )

        lsm.selectRow(1)
        lsm.moveSelectedUp()
        self.assertEqual(lsm.selectedRow(), 0)
        self.assertEqual(len(lsm),3)
        self.assertEqual(lsm[0].name, self.l1.name )
        self.assertEqual(lsm[1].name, self.l3.name )
        self.assertEqual(lsm[2].name, self.l2.name )


        # moving topmost layer up => nothing should happen
        lsm.selectRow(0)
        self.assertEqual(lsm.selectedRow(), 0)
        self.assertEqual(lsm[0].name, self.l1.name )
        self.assertEqual(lsm[1].name, self.l3.name )
        self.assertEqual(lsm[2].name, self.l2.name )
        lsm.moveSelectedUp()
        self.assertEqual(lsm.selectedRow(), 0)
        self.assertEqual(lsm[0].name, self.l1.name )
        self.assertEqual(lsm[1].name, self.l3.name )
        self.assertEqual(lsm[2].name, self.l2.name )

        # moving bottommost layer down => nothing should happen
        lsm.selectRow(2)
        self.assertEqual(lsm.selectedRow(), 2)
        self.assertEqual(lsm[0].name, self.l1.name )
        self.assertEqual(lsm[1].name, self.l3.name )
        self.assertEqual(lsm[2].name, self.l2.name )
        lsm.moveSelectedDown()
        self.assertEqual(lsm.selectedRow(), 2)
        self.assertEqual(lsm[0].name, self.l1.name )
        self.assertEqual(lsm[1].name, self.l3.name )
        self.assertEqual(lsm[2].name, self.l2.name )
コード例 #28
0
# *******************************************************************************

if __name__ == "__main__":
    # make the program quit on Ctrl+C
    import signal

    signal.signal(signal.SIGINT, signal.SIG_DFL)

    import sys, numpy

    from PyQt5.QtWidgets import QPushButton, QHBoxLayout, QVBoxLayout
    from volumina.pixelpipeline.datasources import ArraySource, ConstantSource

    app = QApplication(sys.argv)

    model = LayerStackModel()

    o1 = Layer([ConstantSource()])
    o1.name = "Fancy Layer"
    o1.opacity = 0.5
    model.append(o1)

    o2 = Layer([ConstantSource()])
    o2.name = "Some other Layer"
    o2.opacity = 0.25
    o2.numberOfChannels = 3
    model.append(o2)

    o3 = Layer([ConstantSource()])
    o3.name = "Invisible Layer"
    o3.opacity = 0.15
コード例 #29
0
ファイル: layerwidget_plugin.py プロジェクト: CVML/volumina
 def createWidget(self, parent):      
     model = LayerStackModel()
     
     o1 = Layer()
     o1.name = "Fancy Layer"
     o1.opacity = 0.5
     model.append(o1)
     
     o2 = Layer()
     o2.name = "Some other Layer"
     o2.opacity = 0.25
     model.append(o2)
     
     o3 = Layer()
     o3.name = "Invisible Layer"
     o3.opacity = 0.15
     o3.visible = False
     model.append(o3)
     
     o4 = Layer()
     o4.name = "Fancy Layer II"
     o4.opacity = 0.95
     model.append(o4)
     
     o5 = Layer()
     o5.name = "Fancy Layer III"
     o5.opacity = 0.65
     model.append(o5)
 
     view = LayerWidget(parent, model)
     view.updateGeometry()
     
     return view
コード例 #30
0
class TestLayerWidget(ut.TestCase):
    """
    Create two layers and add them to a LayerWidget.
    Then change one of the layer visibilities and verify that the layer widget appearance updates.
    
    At the time of this writing, the widget doesn't properly repaint the selected layer (all others repaint correctly).
    """
    @classmethod
    def setUpClass(cls):
        if 'TRAVIS' in os.environ:
            # This test fails on Travis-CI for unknown reasons,
            #  probably due to the variability of time.sleep().
            # Skip it on Travis-CI.
            import nose
            raise nose.SkipTest

        cls.app = QApplication([])
        cls.errors = False

    @classmethod
    def tearDownClass(cls):
        del cls.app

    def impl(self):
        try:
            # Change the visibility of the *selected* layer
            self.o2.visible = False

            # Make sure the GUI is caught up on paint events
            QApplication.processEvents()

            # We must sleep for the screenshot to be right.
            time.sleep(0.1)

            self.w.repaint()

            # Capture the window before we change anything
            beforeImg = QPixmap.grabWindow(self.w.winId()).toImage()

            # Change the visibility of the *selected* layer
            self.o2.visible = True

            self.w.repaint()

            # Make sure the GUI is caught up on paint events
            QApplication.processEvents()

            # We must sleep for the screenshot to be right.
            time.sleep(0.1)

            # Capture the window now that we've changed a layer.
            afterImg = QPixmap.grabWindow(self.w.winId()).toImage()

            # Optional: Save the files so we can inspect them ourselves...
            #beforeImg.save('before.png')
            #afterImg.save('after.png')

            # Before and after should NOT match.
            assert beforeImg != afterImg
        except:
            # Catch all exceptions and print them
            # We must finish so we can quit the app.
            import traceback
            traceback.print_exc()
            TestLayerWidget.errors = True

        qApp.quit()

    def test_repaint_after_visible_change(self):
        self.model = LayerStackModel()

        self.o1 = Layer([])
        self.o1.name = "Fancy Layer"
        self.o1.opacity = 0.5
        self.model.append(self.o1)

        self.o2 = Layer([])
        self.o2.name = "Some other Layer"
        self.o2.opacity = 0.25
        self.model.append(self.o2)

        self.view = LayerWidget(None, self.model)
        self.view.show()
        self.view.updateGeometry()

        self.w = QWidget()
        self.lh = QHBoxLayout(self.w)
        self.lh.addWidget(self.view)
        self.w.setGeometry(100, 100, 300, 300)
        self.w.show()
        self.w.raise_()

        # Run the test within the GUI event loop
        QTimer.singleShot(500, self.impl)
        self.app.exec_()

        # Were there errors?
        assert not TestLayerWidget.errors, "There were GUI errors/failures.  See above."
コード例 #31
0
    def __init__(self, parent=None, model=None):
        QListView.__init__(self, parent)

        if model is None:
            model = LayerStackModel()
        self.init(model)
コード例 #32
0
ファイル: imagepump_tests.py プロジェクト: JensNRAD/volumina
    def testAddingAndRemovingLayers( self ):
        lsm = LayerStackModel()
        sims = StackedImageSources( lsm )
        ims_view = sims.viewImageSources()
        self.assertEqual(len(lsm), 0)
        self.assertEqual(len(sims), 0)
        self.assertEqual(len(ims_view), 0)

        lsm.append(self.layer1)
        lsm.append(self.layer2)
        sims.register(self.layer1, self.ims1)
        sims.register(self.layer2, self.ims2)
        self.assertEqual(sims.isRegistered(self.layer1), True)
        self.assertEqual(sims.isRegistered(self.layer2), True)
        self.assertEqual(len(lsm), 2)
        self.assertEqual(len(sims), 2)
        self.assertEqual(len(ims_view), 2)
        self.assertEqual(ims_view[0], self.ims2)
        self.assertEqual(ims_view[1], self.ims1)

        lsm.append(self.layer3)
        self.assertEqual(len(lsm), 3)
        self.assertEqual(len(sims), 2)
        self.assertEqual(len(ims_view), 2)
        self.assertEqual(ims_view[0], self.ims2)
        self.assertEqual(ims_view[1], self.ims1)
        self.assertEqual(sims.isRegistered(self.layer1), True)
        self.assertEqual(sims.isRegistered(self.layer2), True)

        lsm.selectRow(1) # layer2
        lsm.deleteSelected()
        self.assertEqual(len(lsm), 2)
        self.assertEqual(len(sims), 1)
        self.assertEqual(len(ims_view), 1)
        self.assertEqual(ims_view[0], self.ims1)
        self.assertEqual(sims.isRegistered(self.layer1), True)
        self.assertEqual(sims.isRegistered(self.layer2), False)

        lsm.selectRow(0) # layer3
        lsm.deleteSelected()
        self.assertEqual(len(lsm), 1)
        self.assertEqual(len(sims), 1)
        self.assertEqual(len(ims_view), 1)
        self.assertEqual(ims_view[0], self.ims1)
        self.assertEqual(sims.isRegistered(self.layer1), True)
        self.assertEqual(sims.isRegistered(self.layer2), False)

        sims.deregister(self.layer1)
        self.assertEqual(len(lsm), 1)
        self.assertEqual(len(sims), 0)
        self.assertEqual(len(ims_view), 0)
        self.assertEqual(sims.isRegistered(self.layer1), False)
        self.assertEqual(sims.isRegistered(self.layer2), False)
コード例 #33
0
    def testMovingLayers(self):
        lsm = LayerStackModel()
        lsm.append(self.l1)
        lsm.append(self.l2)
        lsm.append(self.l3)
        lsm.selectRow(1)
        self.assertEqual(len(lsm), 3)
        self.assertEqual(lsm[0].name, self.l3.name)
        self.assertEqual(lsm[1].name, self.l2.name)
        self.assertEqual(lsm[2].name, self.l1.name)
        self.assertEqual(lsm.selectedRow(), 1)

        lsm.moveSelectedDown()
        self.assertEqual(lsm.selectedRow(), 2)
        self.assertEqual(len(lsm), 3)
        self.assertEqual(lsm[0].name, self.l3.name)
        self.assertEqual(lsm[1].name, self.l1.name)
        self.assertEqual(lsm[2].name, self.l2.name)

        lsm.selectRow(1)
        lsm.moveSelectedUp()
        self.assertEqual(lsm.selectedRow(), 0)
        self.assertEqual(len(lsm), 3)
        self.assertEqual(lsm[0].name, self.l1.name)
        self.assertEqual(lsm[1].name, self.l3.name)
        self.assertEqual(lsm[2].name, self.l2.name)

        # moving topmost layer up => nothing should happen
        lsm.selectRow(0)
        self.assertEqual(lsm.selectedRow(), 0)
        self.assertEqual(lsm[0].name, self.l1.name)
        self.assertEqual(lsm[1].name, self.l3.name)
        self.assertEqual(lsm[2].name, self.l2.name)
        lsm.moveSelectedUp()
        self.assertEqual(lsm.selectedRow(), 0)
        self.assertEqual(lsm[0].name, self.l1.name)
        self.assertEqual(lsm[1].name, self.l3.name)
        self.assertEqual(lsm[2].name, self.l2.name)

        # moving bottommost layer down => nothing should happen
        lsm.selectRow(2)
        self.assertEqual(lsm.selectedRow(), 2)
        self.assertEqual(lsm[0].name, self.l1.name)
        self.assertEqual(lsm[1].name, self.l3.name)
        self.assertEqual(lsm[2].name, self.l2.name)
        lsm.moveSelectedDown()
        self.assertEqual(lsm.selectedRow(), 2)
        self.assertEqual(lsm[0].name, self.l1.name)
        self.assertEqual(lsm[1].name, self.l3.name)
        self.assertEqual(lsm[2].name, self.l2.name)
コード例 #34
0
ファイル: layerwidget.py プロジェクト: DerThorsten/volumina
# i f   _ _ n a m e _ _   = =   " _ _ m a i n _ _ "                            *
#*******************************************************************************

if __name__ == "__main__":
    #make the program quit on Ctrl+C
    import signal
    signal.signal(signal.SIGINT, signal.SIG_DFL)

    import sys, numpy

    from PyQt4.QtGui import QApplication, QPushButton, QHBoxLayout, QVBoxLayout
    from volumina.pixelpipeline.datasources import ArraySource

    app = QApplication(sys.argv)

    model = LayerStackModel()

    o1 = Layer()
    o1.name = "Fancy Layer"
    o1.opacity = 0.5
    model.append(o1)

    o2 = Layer()
    o2.name = "Some other Layer"
    o2.opacity = 0.25
    model.append(o2)

    o3 = Layer()
    o3.name = "Invisible Layer"
    o3.opacity = 0.15
    o3.visible = False
コード例 #35
0
ファイル: viewer.py プロジェクト: kemaleren/volumina
class Viewer(QMainWindow):
    """High-level API to view multi-dimensional arrays.

    Properties:
        title -- window title

    """
    def __init__(self, parent=None):
        QMainWindow.__init__(self, parent)
        uiDirectory = os.path.split(volumina.__file__)[0]
        if uiDirectory == '':
            uiDirectory = '.'
        loadUi(uiDirectory + '/viewer.ui', self)

        self._dataShape = None
        self._viewerInitialized = False
        self.editor = None
        self.viewingWidget = None
        self.actionQuit.triggered.connect(qApp.quit)
        
        #when connecting in renderScreenshot to a partial(...) function,
        #we need to remember the created function to be able to disconnect
        #to it later
        self._renderScreenshotDisconnect = None

        self.initLayerstackModel()

        self.actionCurrentView = QAction(QIcon(), "Only for selected view", self.menuView)
        f = self.actionCurrentView.font()
        f.setBold(True)
        self.actionCurrentView.setFont(f)

        self.editor = VolumeEditor(self.layerstack)

        #make sure the layer stack widget, which is the right widget
        #managed by the splitter self.splitter shows up correctly
        #TODO: find a proper way of doing this within the designer
        def adjustSplitter():
            s = self.splitter.sizes()
            s = [int(0.66*s[0]), s[0]-int(0.66*s[0])]
            self.splitter.setSizes(s)
        QTimer.singleShot(0, adjustSplitter)
        
    def initLayerstackModel(self):
        self.layerstack = LayerStackModel()
        self.layerWidget.init(self.layerstack)
        model = self.layerstack
        self.UpButton.clicked.connect(model.moveSelectedUp)
        model.canMoveSelectedUp.connect(self.UpButton.setEnabled)
        self.DownButton.clicked.connect(model.moveSelectedDown)
        model.canMoveSelectedDown.connect(self.DownButton.setEnabled)
        self.DeleteButton.clicked.connect(model.deleteSelected)
        model.canDeleteSelected.connect(self.DeleteButton.setEnabled)
    
    @property
    def dataShape(self):
        return self._dataShape
    @dataShape.setter
    def dataShape(self, s):
        if s is None:
            return
        assert len(s) == 5
        
        self._dataShape = s
        self.editor.dataShape = s
        if not self._viewerInitialized:
            self._viewerInitialized = True
            self.viewer.init(self.editor)
            #make sure the data shape is correctly set
            #(some signal/slot connections may be set up in the above init)
            self.editor.dataShape = s

            #if its 2D, maximize the corresponding window
            if len([i for i in list(self.dataShape)[1:4] if i == 1]) == 1:
                viewAxis = [i for i in range(1,4) if self.dataShape[i] != 1][0] - 1
                self.viewer.quadview.switchMinMax(viewAxis)    
        
    def addGrayscaleLayer(self, a, name=None, direct=False):
        source,self.dataShape = createDataSource(a,True)
        layer = GrayscaleLayer(source, direct=direct)
        if name:
            layer.name = name
        self.layerstack.append(layer)
        return layer
        
    def addAlphaModulatedLayer(self, a, name=None):
        source,self.dataShape = createDataSource(a,True)
        layer = AlphaModulatedLayer(source)
        if name:
            layer.name = name
        self.layerstack.append(layer)
        return layer
    
    def addRGBALayer(self, a, name=None):
        source,self.dataShape = createDataSource(a,True)
        layer = RGBALayer(source[0],source[1],source[2])
        if name:
            layer.name = name
        self.layerstack.append(layer)
        return layer

    def addRandomColorsLayer(self, a, name=None, direct=False):
        layer = self.addColorTableLayer(a, name, colortable=None, direct=direct)
        layer.colortableIsRandom = True
        layer.zeroIsTransparent = True
        return layer
    
    def addColorTableLayer(self, a, name=None, colortable=None, direct=False, clickFunctor=None):
        if colortable is None:
            colortable = self._randomColors()
        source,self.dataShape = createDataSource(a,True)
        if clickFunctor is None:
            layer = ColortableLayer(source, colortable, direct=direct)
        else:
            layer = ClickableColortableLayer(self.editor, clickFunctor, source, colortable, direct=direct)
        if name:
            layer.name = name
        self.layerstack.append(layer)
        return layer
    
    def addRelabelingColorTableLayer(self, a, name=None, relabeling=None, colortable=None, direct=False, clickFunctor=None):
        if colortable is None:
            colortable = self._randomColors()
        source = RelabelingArraySource(a)
        if relabeling is None:
            source.setRelabeling(numpy.zeros(numpy.max(a)+1, dtype=a.dtype))
        else:
            source.setRelabeling(relabeling)
        if colortable is None:
            colortable = [QColor(0,0,0,0).rgba(), QColor(255,0,0).rgba()]
        if clickFunctor is None:
            layer = ColortableLayer(source, colortable, direct=direct)
        else:
            layer = ClickableColortableLayer(self.editor, clickFunctor, source, colortable, direct=direct)
        if name:
            layer.name = name 
        self.layerstack.append(layer)
        return (layer, source)
    
    def addClickableSegmentationLayer(self, a, name=None, direct=False):
        M = a.max()
        clickedObjects = dict() #maps from object to the label that is used for it
        usedLabels = set()
        def onClick(layer, pos5D, pos):
            obj = layer.data.originalData[pos5D]
            if obj in clickedObjects:
                layer._datasources[0].setRelabelingEntry(obj, 0)
                usedLabels.remove( clickedObjects[obj] )
                del clickedObjects[obj]
            else:
                labels = sorted(list(usedLabels))
                
                #find first free entry
                if labels:
                    for l in range(1, labels[-1]+2):
                        if l not in labels:
                            break
                    assert l not in usedLabels
                else:
                    l = 1
               
                usedLabels.add(l) 
                clickedObjects[obj] = l
                layer._datasources[0].setRelabelingEntry(obj, l)
        
        colortable = volumina.layer.generateRandomColors(1000, "hsv", {"v": 1.0}, zeroIsTransparent=True)
             
        layer, source = self.addRelabelingColorTableLayer(a, clickFunctor=onClick, name=None,
            relabeling=numpy.zeros(M+1, dtype=a.dtype), colortable=colortable, direct=direct)
        if name is not None:
            layer.name = name
        layer.zeroIsTransparent = True
        layer.colortableIsRandom = True
        return layer 

    def _randomColors(self, M=256):
        """Generates a pleasing color table with M entries."""

        colors = []
        for i in range(M):
            if i == 0:
                colors.append(QColor(0, 0, 0, 0).rgba())
            else:
                h, s, v = random.random(), random.random(), 1.0
                color = numpy.asarray(colorsys.hsv_to_rgb(h, s, v)) * 255
                qColor = QColor(*color)
                colors.append(qColor.rgba())
        return colors
コード例 #36
0
    def testFirstFullyOpaque(self):
        lsm = LayerStackModel()
        sims = StackedImageSources(lsm)
        self.assertEqual(sims.firstFullyOpaque(), None)

        lsm.append(self.layer1)
        lsm.append(self.layer2)
        lsm.append(self.layer3)
        self.assertEqual(lsm.layerIndex(self.layer1), 2)
        self.assertEqual(lsm.layerIndex(self.layer2), 1)
        self.assertEqual(lsm.layerIndex(self.layer3), 0)
        sims.register(self.layer1, self.ims1)
        sims.register(self.layer2, self.ims2)
        sims.register(self.layer3, self.ims3)
        self.assertEqual(sims.firstFullyOpaque(), 0)
        lsm.clear()

        sims = StackedImageSources(lsm)
        lsm.append(self.layer2)
        lsm.append(self.layer3)
        lsm.append(self.layer1)
        self.assertEqual(lsm.layerIndex(self.layer1), 0)
        self.assertEqual(lsm.layerIndex(self.layer2), 2)
        self.assertEqual(lsm.layerIndex(self.layer3), 1)
        sims.register(self.layer1, self.ims1)
        sims.register(self.layer2, self.ims2)
        sims.register(self.layer3, self.ims3)
        self.assertEqual(sims.firstFullyOpaque(), 1)
        lsm.clear()

        sims = StackedImageSources(lsm)
        lsm.append(self.layer2)
        lsm.append(self.layer1)
        self.assertEqual(lsm.layerIndex(self.layer1), 0)
        self.assertEqual(lsm.layerIndex(self.layer2), 1)
        sims.register(self.layer1, self.ims1)
        sims.register(self.layer2, self.ims2)
        self.assertEqual(sims.firstFullyOpaque(), None)
        lsm.clear()
コード例 #37
0
    def testAddingAndRemovingLayers(self):
        lsm = LayerStackModel()
        sims = StackedImageSources(lsm)
        ims_view = sims.viewImageSources()
        self.assertEqual(len(lsm), 0)
        self.assertEqual(len(sims), 0)
        self.assertEqual(len(ims_view), 0)

        lsm.append(self.layer1)
        lsm.append(self.layer2)
        sims.register(self.layer1, self.ims1)
        sims.register(self.layer2, self.ims2)
        self.assertEqual(sims.isRegistered(self.layer1), True)
        self.assertEqual(sims.isRegistered(self.layer2), True)
        self.assertEqual(len(lsm), 2)
        self.assertEqual(len(sims), 2)
        self.assertEqual(len(ims_view), 2)
        self.assertEqual(ims_view[0], self.ims2)
        self.assertEqual(ims_view[1], self.ims1)

        lsm.append(self.layer3)
        self.assertEqual(len(lsm), 3)
        self.assertEqual(len(sims), 2)
        self.assertEqual(len(ims_view), 2)
        self.assertEqual(ims_view[0], self.ims2)
        self.assertEqual(ims_view[1], self.ims1)
        self.assertEqual(sims.isRegistered(self.layer1), True)
        self.assertEqual(sims.isRegistered(self.layer2), True)

        lsm.selectRow(1)  # layer2
        lsm.deleteSelected()
        self.assertEqual(len(lsm), 2)
        self.assertEqual(len(sims), 1)
        self.assertEqual(len(ims_view), 1)
        self.assertEqual(ims_view[0], self.ims1)
        self.assertEqual(sims.isRegistered(self.layer1), True)
        self.assertEqual(sims.isRegistered(self.layer2), False)

        lsm.selectRow(0)  # layer3
        lsm.deleteSelected()
        self.assertEqual(len(lsm), 1)
        self.assertEqual(len(sims), 1)
        self.assertEqual(len(ims_view), 1)
        self.assertEqual(ims_view[0], self.ims1)
        self.assertEqual(sims.isRegistered(self.layer1), True)
        self.assertEqual(sims.isRegistered(self.layer2), False)

        sims.deregister(self.layer1)
        self.assertEqual(len(lsm), 1)
        self.assertEqual(len(sims), 0)
        self.assertEqual(len(ims_view), 0)
        self.assertEqual(sims.isRegistered(self.layer1), False)
        self.assertEqual(sims.isRegistered(self.layer2), False)
コード例 #38
0
    def createWidget(self, parent):
        model = LayerStackModel()

        o1 = Layer()
        o1.name = "Fancy Layer"
        o1.opacity = 0.5
        model.append(o1)

        o2 = Layer()
        o2.name = "Some other Layer"
        o2.opacity = 0.25
        model.append(o2)

        o3 = Layer()
        o3.name = "Invisible Layer"
        o3.opacity = 0.15
        o3.visible = False
        model.append(o3)

        o4 = Layer()
        o4.name = "Fancy Layer II"
        o4.opacity = 0.95
        model.append(o4)

        o5 = Layer()
        o5.name = "Fancy Layer III"
        o5.opacity = 0.65
        model.append(o5)

        view = LayerWidget(parent, model)
        view.updateGeometry()

        return view
コード例 #39
0
ファイル: viewer.py プロジェクト: jakirkham/volumina
class Viewer(QMainWindow):
    """High-level API to view multi-dimensional arrays.

    Properties:
        title -- window title

    """
    def __init__(self, parent=None):
        QMainWindow.__init__(self, parent)
        uiDirectory = os.path.split(volumina.__file__)[0]
        if uiDirectory == '':
            uiDirectory = '.'
        loadUi(uiDirectory + '/viewer.ui', self)

        self._dataShape = None
        self._viewerInitialized = False
        self.editor = None
        self.viewingWidget = None
        self.actionQuit.triggered.connect(qApp.quit)
        
        #when connecting in renderScreenshot to a partial(...) function,
        #we need to remember the created function to be able to disconnect
        #to it later
        self._renderScreenshotDisconnect = None

        self.initLayerstackModel()

        self.actionCurrentView = QAction(QIcon(), "Only for selected view", self.menuView)
        f = self.actionCurrentView.font()
        f.setBold(True)
        self.actionCurrentView.setFont(f)

        # Lazy import here to prevent this module from ignoring volumine.NO3D flag.
        from volumina.volumeEditor import VolumeEditor
        self.editor = VolumeEditor(self.layerstack, parent=self)

        #make sure the layer stack widget, which is the right widget
        #managed by the splitter self.splitter shows up correctly
        #TODO: find a proper way of doing this within the designer
        def adjustSplitter():
            s = self.splitter.sizes()
            s = [int(0.66*s[0]), s[0]-int(0.66*s[0])]
            self.splitter.setSizes(s)
        QTimer.singleShot(0, adjustSplitter)
        
    @property
    def title(self):
        return self.windowTitle()
    
    @title.setter
    def title(self, t):
        self.setWindowTitle(t)
        
    def initLayerstackModel(self):
        self.layerstack = LayerStackModel()
        self.layerWidget.init(self.layerstack)
        model = self.layerstack
        self.UpButton.clicked.connect(model.moveSelectedUp)
        model.canMoveSelectedUp.connect(self.UpButton.setEnabled)
        self.DownButton.clicked.connect(model.moveSelectedDown)
        model.canMoveSelectedDown.connect(self.DownButton.setEnabled)
        self.DeleteButton.clicked.connect(model.deleteSelected)
        model.canDeleteSelected.connect(self.DeleteButton.setEnabled)
    
    @property
    def dataShape(self):
        return self._dataShape
    @dataShape.setter
    def dataShape(self, s):
        if s is None:
            return
        assert len(s) == 5
        
        self._dataShape = s
        self.editor.dataShape = s
        if not self._viewerInitialized:
            self._viewerInitialized = True
            self.viewer.init(self.editor)
            #make sure the data shape is correctly set
            #(some signal/slot connections may be set up in the above init)
            self.editor.dataShape = s

            #FIXME: this code is broken
            #if its 2D, maximize the corresponding window
            #if len([i for i in list(self.dataShape)[1:4] if i == 1]) == 1:
            #    viewAxis = [i for i in range(1,4) if self.dataShape[i] == 1][0] - 1
            #    self.viewer.quadview.switchMinMax(viewAxis)    
        
    def addGrayscaleLayer(self, a, name=None, direct=False):
        source,self.dataShape = createDataSource(a,True)
        layer = GrayscaleLayer(source, direct=direct)
        layer.numberOfChannels = self.dataShape[-1]
        if name:
            layer.name = name
        self.layerstack.append(layer)
        return layer
        
    def addAlphaModulatedLayer(self, a, name=None, **kwargs):
        source,self.dataShape = createDataSource(a,True)
        layer = AlphaModulatedLayer(source, **kwargs)
        if name:
            layer.name = name
        self.layerstack.append(layer)
        return layer
    
    def addRGBALayer(self, a, name=None):
        assert a.shape[2] >= 3
        sources = [None, None, None,None]
        for i in range(3):
            sources[i], self.dataShape = createDataSource(a[...,i], True)
        if(a.shape[-1] >= 4):
            sources[3], self.dataShape = createDataSource(a[...,3], True) 
        layer = RGBALayer(sources[0],sources[1],sources[2], sources[3])
        if name:
            layer.name = name
        self.layerstack.append(layer)
        return layer

    def addRandomColorsLayer(self, a, name=None, direct=False):
        layer = self.addColorTableLayer(a, name, colortable=None, direct=direct)
        layer.colortableIsRandom = True
        layer.zeroIsTransparent = True
        return layer
    
    def addColorTableLayer(self, a, name=None, colortable=None, direct=False, clickFunctor=None):
        if colortable is None:
            colortable = self._randomColors()
        source,self.dataShape = createDataSource(a,True)
        if clickFunctor is None:
            layer = ColortableLayer(source, colortable, direct=direct)
        else:
            layer = ClickableColortableLayer(self.editor, clickFunctor, source, colortable, direct=direct)
        if name:
            layer.name = name
        self.layerstack.append(layer)
        return layer
    
    def addRelabelingColorTableLayer(self, a, name=None, relabeling=None, colortable=None, direct=False, clickFunctor=None, right=True):
        if colortable is None:
            colortable = self._randomColors()
        source = RelabelingArraySource(a)
        if relabeling is None:
            source.setRelabeling(numpy.zeros(numpy.max(a)+1, dtype=a.dtype))
        else:
            source.setRelabeling(relabeling)
        if colortable is None:
            colortable = [QColor(0,0,0,0).rgba(), QColor(255,0,0).rgba()]
        if clickFunctor is None:
            layer = ColortableLayer(source, colortable, direct=direct)
        else:
            layer = ClickableColortableLayer(self.editor, clickFunctor, source, colortable, direct=direct, right=right)
        if name:
            layer.name = name 
        self.layerstack.append(layer)
        return (layer, source)
    
    def addClickableSegmentationLayer(self, a, name=None, direct=False, colortable=None, reuseColors=True):
        return ClickableSegmentationLayer(a, self, name=name, direct=direct, colortable=colortable, reuseColors=reuseColors) 
        
    def _randomColors(self, M=256):
        """Generates a pleasing color table with M entries."""

        colors = []
        for i in range(M):
            if i == 0:
                colors.append(QColor(0, 0, 0, 0).rgba())
            else:
                h, s, v = random.random(), random.random(), 1.0
                color = numpy.asarray(colorsys.hsv_to_rgb(h, s, v)) * 255
                qColor = QColor(*color)
                colors.append(qColor.rgba())
        #for the first 16 objects, use some colors that are easily distinguishable
        colors[1:17] = colortables.default16 
        return colors
コード例 #40
0
    def testAddingAndRemoving(self):
        lsm = LayerStackModel()
        self.assertEqual(len(lsm), 0)

        lsm.append(self.l1)
        self.assertEqual(len(lsm), 1)
        self.assertEqual(lsm[0].name, self.l1.name)

        lsm.append(self.l2)
        self.assertEqual(len(lsm), 2)
        self.assertEqual(lsm[0].name, self.l2.name)
        self.assertEqual(lsm[1].name, self.l1.name)

        lsm.insert(1, self.l3)
        self.assertEqual(len(lsm), 3)
        self.assertEqual(lsm[0].name, self.l2.name)
        self.assertEqual(lsm[1].name, self.l3.name)
        self.assertEqual(lsm[2].name, self.l1.name)

        lsm.selectRow(0)
        lsm.deleteSelected()
        self.assertEqual(len(lsm), 2)
        self.assertEqual(lsm[0].name, self.l3.name)
        self.assertEqual(lsm[1].name, self.l1.name)

        lsm.clear()
        self.assertEqual(len(lsm), 0)
コード例 #41
0
ファイル: imagepump_tests.py プロジェクト: JensNRAD/volumina
    def testFirstFullyOpaque( self ):
        lsm = LayerStackModel()
        sims = StackedImageSources( lsm )
        self.assertEqual(sims.firstFullyOpaque(), None)

        lsm.append(self.layer1)
        lsm.append(self.layer2)
        lsm.append(self.layer3)
        self.assertEqual( lsm.layerIndex(self.layer1), 2 )
        self.assertEqual( lsm.layerIndex(self.layer2), 1 )
        self.assertEqual( lsm.layerIndex(self.layer3), 0 )
        sims.register(self.layer1, self.ims1)
        sims.register(self.layer2, self.ims2)
        sims.register(self.layer3, self.ims3)
        self.assertEqual(sims.firstFullyOpaque(), 0)
        lsm.clear()

        sims = StackedImageSources( lsm )
        lsm.append(self.layer2)
        lsm.append(self.layer3)
        lsm.append(self.layer1)
        self.assertEqual( lsm.layerIndex(self.layer1), 0 )
        self.assertEqual( lsm.layerIndex(self.layer2), 2 )
        self.assertEqual( lsm.layerIndex(self.layer3), 1 )
        sims.register(self.layer1, self.ims1)
        sims.register(self.layer2, self.ims2)
        sims.register(self.layer3, self.ims3)
        self.assertEqual(sims.firstFullyOpaque(), 1)
        lsm.clear()

        sims = StackedImageSources( lsm )
        lsm.append(self.layer2)
        lsm.append(self.layer1)
        self.assertEqual( lsm.layerIndex(self.layer1), 0 )
        self.assertEqual( lsm.layerIndex(self.layer2), 1 )
        sims.register(self.layer1, self.ims1)
        sims.register(self.layer2, self.ims2)
        self.assertEqual(sims.firstFullyOpaque(), None)
        lsm.clear()
コード例 #42
0
ファイル: lazy_test.py プロジェクト: lfiaschi/volumina
    class ImageScene2D_LazyTest(ut.TestCase):
        @classmethod
        def setUpClass(cls):
            cls.app = None
            if QApplication.instance():
                cls.app = QApplication.instance()
            else:
                cls.app = QApplication([], False)

        @classmethod
        def tearDownClass(cls):
            del cls.app

        def setUp(self):
            self.layerstack = LayerStackModel()
            self.sims = StackedImageSources(self.layerstack)

            self.g = Graph()
            self.op = OpLazy(self.g)
            self.ds = LazyflowSource(self.op.Output)

            self.ss = SliceSource(self.ds, projectionAlongTZC)

            self.layer = GrayscaleLayer(self.ds)
            self.layerstack.append(self.layer)
            self.ims = imsfac.createImageSource(self.layer, [self.ss])
            self.sims.register(self.layer, self.ims)

            self.scene = ImageScene2D(PositionModel(), (0, 0, 0),
                                      preemptive_fetch_number=0)
            self.scene.setCacheSize(1)

            self.scene.stackedImageSources = self.sims
            self.scene.dataShape = (30, 30)

        def tearDown(self):
            if self.scene._tileProvider:
                self.scene._tileProvider.notifyThreadsToStop()
                self.scene._tileProvider.joinThreads()

        def renderScene(self, s, exportFilename=None, joinRendering=True):
            img = QImage(30, 30, QImage.Format_ARGB32_Premultiplied)
            img.fill(Qt.white)
            p = QPainter(img)

            s.render(p)  #trigger a rendering of the whole scene
            if joinRendering:
                #wait for all the data to arrive
                s.joinRendering()
                #finally, render everything
                s.render(p)
            p.end()

            if exportFilename is not None:
                img.save(exportFilename)
            return byte_view(img)

        def testLazy(self):
            for i in range(3):
                self.op.setConstant(i)
                aimg = self.renderScene(self.scene, "/tmp/a_%03d.png" % i)
                assert numpy.all(
                    aimg[:, :,
                         0] == i), "!= %d, [0,0,0]=%d" % (i, aimg[0, 0, 0])

                self.op.setConstant(42)
                self.op.setDelay(1)
                aimg = self.renderScene(self.scene,
                                        joinRendering=False,
                                        exportFilename="/tmp/x_%03d.png" % i)
                #this should be "i", not 255 (the default background for the imagescene)
                assert numpy.all(
                    aimg[:, :,
                         0] == i), "!= %d, [0,0,0]=%d" % (i, aimg[0, 0, 0])
コード例 #43
0
ファイル: api.py プロジェクト: LimpingTwerp/volumina
class Viewer(QMainWindow):
    """High-level API to view multi-dimensional arrays.

    Properties:
        title -- window title

    """
    def __init__(self, parent=None):
        QMainWindow.__init__(self, parent)
        uiDirectory = os.path.split(volumina.__file__)[0]
        if uiDirectory == '':
            uiDirectory = '.'
        loadUi(uiDirectory + '/viewer.ui', self)

        self._dataShape = None
        self.editor = None

        self.actionQuit.triggered.connect(qApp.quit)
        #when connecting in renderScreenshot to a partial(...) function,
        #we need to remember the created function to be able to disconnect
        #to it later
        self._renderScreenshotDisconnect = None

        self.initLayerstackModel()

        self.actionCurrentView = QAction(QIcon(), \
            "Only for selected view", self.menuView)
        f = self.actionCurrentView.font()
        f.setBold(True)
        self.actionCurrentView.setFont(f)

        #make sure the layer stack widget, which is the right widget
        #managed by the splitter self.splitter shows up correctly
        #TODO: find a proper way of doing this within the designer
        def adjustSplitter():
            s = self.splitter.sizes()
            s = [int(0.66*s[0]), s[0]-int(0.66*s[0])]
            self.splitter.setSizes(s)
        QTimer.singleShot(0, adjustSplitter)

    def initLayerstackModel(self):
        self.layerstack = LayerStackModel()
        self.layerWidget.init(self.layerstack)
        model = self.layerstack
        self.UpButton.clicked.connect(model.moveSelectedUp)
        model.canMoveSelectedUp.connect(self.UpButton.setEnabled)
        self.DownButton.clicked.connect(model.moveSelectedDown)
        model.canMoveSelectedDown.connect(self.DownButton.setEnabled)
        self.DeleteButton.clicked.connect(model.deleteSelected)
        model.canDeleteSelected.connect(self.DeleteButton.setEnabled)

    def renderScreenshot(self, axis, blowup=1, filename="/tmp/volumina_screenshot.png"):
        """Save the complete slice as shown by the slice view 'axis'
        in the GUI as an image
        
        axis -- 0, 1, 2 (x, y, or z slice view)
        blowup -- enlarge written image by this factor
        filename -- output file
        """

        print "Rendering screenshot for axis=%d to '%s'" % (axis, filename)
        s = self.editor.imageScenes[axis]
        self.editor.navCtrl.enableNavigation = False
        func = partial(self._renderScreenshot, s, blowup, filename)
        self._renderScreenshotDisconnect = func
        s._renderThread.patchAvailable.connect(func)
        nRequested = 0
        for patchNumber in range(len(s._tiling)):
            p = s.tileProgress(patchNumber)
            if p < 1.0:
                s.requestPatch(patchNumber)
                nRequested += 1
        print "  need to compute %d of %d patches" % (nRequested, len(s._tiling))
        if nRequested == 0:
            #If no tile needed to be requested, the 'patchAvailable' signal
            #of the render thread will never come.
            #In this case, we need to call the implementation ourselves:
            self._renderScreenshot(s, blowup, filename, patchNumber=0)

    def addLayer(self, a, display='grayscale', opacity=1.0, \
                 name='Unnamed Layer', visible=True, interpretChannelsAs=None):
        print "adding layer '%s', shape=%r, %r" % (name, a.shape, type(a))

        """Adds a new layer on top of the layer stack (such that it will be
        above all currently defined layers). The array 'a' may be a simple
        numpy.ndarray or implicitly defined via a LazyflowArraySource.

        Returns the created Layer object. The layer can either be removed
        by passing this object to self.removeLayer, or by giving a unique
        name.
        """

        aSlices = None #in case a needs to be split by a lazyflow operator


        if len(a.shape) not in [2,3,5]:
            raise RuntimeError("Cannot interpret array with: shape=%r" \
                               % a.shape)

        volumeImage = True
        if len(a.shape) == 2:
            volumeImage = False
        if len(a.shape) == 3 and a.shape[2] == 3 and interpretChannelsAs == 'RGB':
            volumeImage = False
        viewerType = "volume 5D"
        if not volumeImage: viewerType = "image 2D"
        print "  treating as %s" % viewerType

        aType = None
        if 'lazyflow' in a.__class__.__module__:
            aType = 'lazyflow'
        elif hasattr(a, 'axistags'):
            aType = 'vigra'
        elif isinstance(a, numpy.ndarray):
            aType = 'numpy'
        else:
            aType = 'generic'

        #
        # construct a canonical form for arrays:
        #
        # 2D: x,y,c (to be viewed with image viewer)
        # 5D: t,x,y,z,c (to be viewed with volume viewer)
        #

        #convert from LAZYFLOW
        if aType == 'lazyflow':
            Source = LazyflowSource
            if volumeImage:
                if len(a.shape) < 5:
                    o = Op5ifyer(a.operator.graph)
                    o.inputs['Input'].connect(a)
                    a = o.outputs['Output']
            elif not volumeImage:
                o = OpMultiArraySlicer(a.operator.graph)
                o.inputs['Input'].connect(a)
                o.inputs['AxisFlag'].setValue('c')
                aSlices = o.outputs['Slices']
                class A:
                    pass
                a = A(); a.shape = aSlices[0].shape

        #convert from VIGRANUMPY ARRAY
        elif aType == 'vigra':
            if volumeImage:
                #vigra array with axistags
                a = a.withAxes('t', 'x', 'y', 'z', 'c').view(numpy.ndarray)
            else:
                a = a.withAxes('x', 'y', 'c').view(numpy.ndarray)
            Source = ArraySource

        #convert from NUMPY ARRAY
        elif aType == 'numpy':
            if volumeImage:
                if len(a.shape) == 3:
                    a = a[numpy.newaxis, ..., numpy.newaxis]
                elif len(a.shape) != 5:
                    raise RuntimeError("Cannot interpret numpy array with shape %r as 5D volume" % (a.shape,))
            Source = ArraySource

        #convert from GENERIC ARRAY
        elif aType == 'generic': 
            # not a numpy array. Maybe h5py or something else. Embed it.
            if(hasattr(a, 'dtype')):
                a = Array5d(a, dtype=a.dtype)
            else:
                a = Array5d(a, dtype=np.uint8)
            Source = ArraySource

        #
        # initialize the proper viewer (2D or 5D)
        #

        if not volumeImage:
            init = self._initImageViewing
            shape = a.shape[0:2] #2D
            instance = ImageEditor
        else:
            init = self._initVolumeViewing
            shape = a.shape #5D
            instance = VolumeEditor

        if self.editor is None or self.editor.dataShape != shape:
            if self.editor:
                print "  new %s layer '%s', shape %r is not compatible with existing shape %r" % (viewerType, name, shape, self.editor.dataShape)
            if not isinstance(self.editor, instance) or self.editor is None:
                init()
            self.editor.dataShape = shape
            print "  --> resetting viewer to shape=%r and zero layers" % (self.editor.dataShape,) 
            self.layerstack.clear()

        #
        # create layer
        #

        if display == 'grayscale':
            if interpretChannelsAs == None:
                source = Source(a)
                type_info = numpy.iinfo(a.dtype)
                if type_info.min < 0:
                    print "WARNING: datatype is not bound to semi-positive values"
                layer = GrayscaleLayer(source, range=(0, type_info.max))
            elif interpretChannelsAs == "RGB":
                if aSlices is not None:
                    layer = RGBALayer(LazyflowSource(aSlices[0]), LazyflowSource(aSlices[1]), LazyflowSource(aSlices[2])) 
                else:
                    assert len(a.shape) == 3
                    layer = RGBALayer(Source(a[:,:,0]), Source(a[:,:,1]), Source(a[:,:,2]))
        elif display == 'randomcolors':
            if a.dtype != numpy.uint8:
                print "layer '%s': implicit conversion from %s to uint8" \
                      % (name, a.dtype)
                if a.dtype == numpy.uint32:
                    a = a.astype(numpy.uint8)
                else:
                    raise RuntimeError("unhandled dtype=%r" % a.dtype)
            source = Source(a)
            layer = ColortableLayer(source, self._randomColors())
        else:
            raise RuntimeError("unhandled type of overlay")

        layer.name = name
        layer.opacity = opacity
        layer.visible = visible
        self.layerstack.append(layer)

        return layer

    def removeLayer(self, layer):
        """Remove layer either by given 'Layer' object
        (as returned by self.addLayer), or by it's name string
        (as given to the name parameter in self.addLayer)"""

        if isinstance(layer, Layer):
            idx = self.layerstack.layerIndex(layer)
            self.layerstack.removeRows(idx, 1)
        else:
            idx = [i for i in range(len(self.layerstack)) if \
                self.layerstack.data(self.layerstack.index(i)).name == layer]
            if len(idx) > 1:
                raise RuntimeError("Trying to remove layer '%s', whose name is"
                    "ambigous as it refers to %d layers" % len(idx))
                return False
            self.layerstack.removeRows(idx[0], 1)
        return True

    @property
    def title(self):
        """Get the window title"""

        return self.windowTitle()

    @title.setter
    def title(self, t):
        """Set the window title"""
        
        self.setWindowTitle(t)

    ### private implementations

    def _initVolumeViewing(self):
        self.initLayerstackModel()

        self.editor = VolumeEditor(self.layerstack, labelsink=None)

        if not isinstance(self.viewer, VolumeEditorWidget) or self.viewer.editor is None:
            splitterSizes = self.splitter.sizes()
            self.viewer.setParent(None)
            del self.viewer
            self.viewer = VolumeEditorWidget()
            self.splitter.insertWidget(0, self.viewer)
            self.splitter.setSizes(splitterSizes)
            self.viewer.init(self.editor)

            w = self.viewer
            self.menuView.addAction(w.allZoomToFit)
            self.menuView.addAction(w.allToggleHUD)
            self.menuView.addAction(w.allCenter)
            self.menuView.addSeparator()
            self.menuView.addAction(self.actionCurrentView)
            self.menuView.addAction(w.selectedZoomToFit)
            self.menuView.addAction(w.toggleSelectedHUD)
            self.menuView.addAction(w.selectedCenter)
            self.menuView.addAction(w.selectedZoomToOriginal)
            self.menuView.addAction(w.rubberBandZoom)

            self.editor.newImageView2DFocus.connect(self._setIconToViewMenu)

    def _initImageViewing(self):

        if not isinstance(self.viewer, ImageEditorWidget):
            self.initLayerstackModel()
            
            w = self.viewer
            if isinstance(w, VolumeEditor) and w.editor is not None:
                self.menuView.removeAction(w.allZoomToFit)
                self.menuView.removeAction(w.allToggleHUD)
                self.menuView.removeAction(w.allCenter)
                self.menuView.removeAction(self.actionCurrentView)
                self.menuView.removeAction(w.selectedZoomToFit)
                self.menuView.removeAction(w.toggleSelectedHUD)
                self.menuView.removeAction(w.selectedCenter)
                self.menuView.removeAction(w.selectedZoomToOriginal)
                self.menuView.removeAction(w.rubberBandZoom)
                
            

            #remove 3D viewer
            splitterSizes = self.splitter.sizes()
            self.viewer.setParent(None)
            del self.viewer

            self.viewer = ImageEditorWidget()
            self.editor = ImageEditor(layerStackModel=self.layerstack)
            self.viewer.init(self.editor)
            self.splitter.insertWidget(0, self.viewer)
            self.splitter.setSizes(splitterSizes)
            
            if not _has_lazyflow:
                self.viewer.setEnabled(False)
                
    def _renderScreenshot(self, s, blowup, filename, patchNumber):
        progress = 0
        for patchNumber in range(len(s._tiling)):
            p = s.tileProgress(patchNumber) 
            progress += p
        progress = progress/float(len(s._tiling))
        if progress == 1.0:
            s._renderThread.patchAvailable.disconnect(self._renderScreenshotDisconnect)
            
            img = QImage(int(round((blowup*s.sceneRect().size().width()))),
                         int(round((blowup*s.sceneRect().size().height()))),
                         QImage.Format_ARGB32)
            screenshotPainter = QPainter(img)
            screenshotPainter.setRenderHint(QPainter.Antialiasing, True)
            s.render(screenshotPainter, QRectF(0, 0, img.width()-1, img.height()-1), s.sceneRect())
            print "  saving to '%s'" % filename
            img.save(filename)
            del screenshotPainter
            self.editor.navCtrl.enableNavigation = True

    def _setIconToViewMenu(self):
        focused = self.editor.imageViews[self.editor._lastImageViewFocus]
        self.actionCurrentView.setIcon(\
            QIcon(focused._hud.axisLabel.pixmap()))

    def _randomColors(self, M=256):
        """Generates a pleasing color table with M entries."""

        colors = []
        for i in range(M):
            if i == 0:
                colors.append(QColor(0, 0, 0, 0).rgba())
            else:
                h, s, v = random.random(), random.random(), 1.0
                color = numpy.asarray(colorsys.hsv_to_rgb(h, s, v)) * 255
                qColor = QColor(*color)
                colors.append(qColor.rgba())
        return colors
    
    def show(self):
        if not _has_lazyflow:
            popUp = QMessageBox(parent=self)
            popUp.setTextFormat(1)
            popUp.setText("<font size=\"4\"> Lazyflow could not be imported:</font> <br><br><b><font size=\"4\" color=\"#8A0808\">%s</font></b>"%(exceptStr))
            popUp.show()
            popUp.exec_()
        QMainWindow.show(self)
コード例 #44
0
class ImageScene2D_RenderTest( ut.TestCase ):

    @classmethod
    def setUpClass(cls):
        cls.app = None
        if QApplication.instance():
            cls.app = QApplication.instance()
        else:
            cls.app = QApplication([], False)

    @classmethod
    def tearDownClass(cls):
        del cls.app

    def setUp( self ):
        self.layerstack = LayerStackModel()
        self.sims = StackedImageSources( self.layerstack )

        self.GRAY = 201
        self.ds = ConstantSource(self.GRAY)
        self.layer = GrayscaleLayer( self.ds )
        self.layerstack.append(self.layer)
        self.ims = imsfac.createImageSource( self.layer, [self.ds] )
        self.sims.register(self.layer, self.ims)

        self.scene = ImageScene2D(PositionModel(), (0,3,4), preemptive_fetch_number=0)

        self.scene.stackedImageSources = self.sims
        self.scene.dataShape = (310,290)

    def tearDown( self ):
        if self.scene._tileProvider:
            self.scene._tileProvider.notifyThreadsToStop()
            self.scene._tileProvider.joinThreads()

    def renderScene( self, s, exportFilename=None):
        img = QImage(310,290,QImage.Format_ARGB32_Premultiplied)
        p = QPainter(img)
        s.render(p)
        s.joinRendering()
        s.render(p)
        p.end()
        if exportFilename is not None:
            img.save(exportFilename)
        return byte_view(img)

    def testBasicImageRenderingCapability( self ):
        aimg = self.renderScene(self.scene)
        self.assertTrue(np.all(aimg[:,:,0:3] == self.GRAY))
        self.assertTrue(np.all(aimg[:,:,3] == 255))

    def testToggleVisibilityOfOneLayer( self ):
        aimg = self.renderScene(self.scene)
        self.assertTrue(np.all(aimg[:,:,0:3] == self.GRAY))
        self.assertTrue(np.all(aimg[:,:,3] == 255))

        self.layer.visible = False
        aimg = self.renderScene(self.scene)
        self.assertTrue(np.all(aimg[:,:,0:3] == 255)) # all white
        self.assertTrue(np.all(aimg[:,:,3] == 255))

        self.layer.visible = True
        aimg = self.renderScene(self.scene)
        self.assertTrue(np.all(aimg[:,:,0:3] == self.GRAY))
        self.assertTrue(np.all(aimg[:,:,3] == 255))
コード例 #45
0
ファイル: tiling_tests.py プロジェクト: LimpingTwerp/volumina
class DirtyPropagationTest( ut.TestCase ):
    
    def setUp( self ):
        dataShape = (1, 900, 400, 10, 1) # t,x,y,z,c
        data = np.indices(dataShape)[3] # Data is labeled according to z-index
        self.ds1 = ArraySource( data )
        self.CONSTANT = 13
        self.ds2 = ConstantSource( self.CONSTANT )

        self.layer1 = GrayscaleLayer( self.ds1 )
        self.layer1.visible = True
        self.layer1.opacity = 1.0

        self.layer2 = GrayscaleLayer( self.ds2 )

        self.lsm = LayerStackModel()
        self.pump = ImagePump( self.lsm, SliceProjection() )

    def testEverythingDirtyPropagation( self ):
        self.lsm.append(self.layer2)        
        tiling = Tiling((900,400), blockSize=100)
        tp = TileProvider(tiling, self.pump.stackedImageSources)
        try:
            tp.requestRefresh(QRectF(100,100,200,200))
            tp.join()
            tiles = tp.getTiles(QRectF(100,100,200,200))
            for tile in tiles:
                aimg = byte_view(tile.qimg)
                self.assertTrue(np.all(aimg[:,:,0:3] == self.CONSTANT))
                self.assertTrue(np.all(aimg[:,:,3] == 255))

            NEW_CONSTANT = self.CONSTANT+1
            self.ds2.constant = NEW_CONSTANT
            tp.requestRefresh(QRectF(100,100,200,200))
            tp.join()
            tiles = tp.getTiles(QRectF(100,100,200,200))
            for tile in tiles:
                aimg = byte_view(tile.qimg)
                self.assertTrue(np.all(aimg[:,:,0:3] == NEW_CONSTANT))
                self.assertTrue(np.all(aimg[:,:,3] == 255))
            
        finally:
            tp.notifyThreadsToStop()
            tp.joinThreads()

    def testOutOfViewDirtyPropagation( self ):
        self.lsm.append(self.layer1)
        tiling = Tiling((900,400), blockSize=100)
        tp = TileProvider(tiling, self.pump.stackedImageSources)
        try:
            # Navigate down to the second z-slice
            self.pump.syncedSliceSources.through = [0,1,0]
            tp.requestRefresh(QRectF(100,100,200,200))
            tp.join()

            # Sanity check: Do we see the right data on the second slice? (should be all 1s)
            tiles = tp.getTiles(QRectF(100,100,200,200))
            for tile in tiles:
                aimg = byte_view(tile.qimg)
                self.assertTrue(np.all(aimg[:,:,0:3] == 1))
                self.assertTrue(np.all(aimg[:,:,3] == 255))

            # Navigate down to the third z-slice
            self.pump.syncedSliceSources.through = [0,2,0]
            tp.requestRefresh(QRectF(100,100,200,200))
            tp.join()

            # Sanity check: Do we see the right data on the third slice?(should be all 2s)
            tiles = tp.getTiles(QRectF(100,100,200,200))
            for tile in tiles:
                aimg = byte_view(tile.qimg)
                self.assertTrue(np.all(aimg[:,:,0:3] == 2))
                self.assertTrue(np.all(aimg[:,:,3] == 255))

            # Navigate back up to the second z-slice
            self.pump.syncedSliceSources.through = [0,1,0]
            tp.requestRefresh(QRectF(100,100,200,200))
            tp.join()
            for tile in tiles:
                aimg = byte_view(tile.qimg)
                self.assertTrue(np.all(aimg[:,:,0:3] == 1))
                self.assertTrue(np.all(aimg[:,:,3] == 255))

            # Change some of the data in the (out-of-view) third z-slice
            slicing = (slice(None), slice(100,300), slice(100,300), slice(2,3), slice(None))
            slicing = tuple(slicing)
            self.ds1._array[slicing] = 99
            self.ds1.setDirty( slicing )
            
            # Navigate back down to the third z-slice
            self.pump.syncedSliceSources.through = [0,2,0]
            tp.requestRefresh(QRectF(100,100,200,200))
            tp.join()

            # Even though the data was out-of-view when it was changed, it should still have new values.
            # If dirtiness wasn't propagated correctly, the cache's old values will be used.
            # (For example, this fails if you comment out the call to setDirty, above.)
            tiles = tp.getTiles(QRectF(100,100,200,200))
            for tile in tiles:
                aimg = byte_view(tile.qimg)
                # Use any() because the tile borders may not be perfectly aligned with the data we changed.
                self.assertTrue(np.any(aimg[:,:,0:3] == 99))

        finally:
            tp.notifyThreadsToStop()
            tp.joinThreads()
コード例 #46
0
ファイル: lazy_test.py プロジェクト: buotex/volumina
    class ImageScene2D_LazyTest( ut.TestCase ):

        @classmethod
        def setUpClass(cls):
            cls.app = None
            if QApplication.instance():
                cls.app = QApplication.instance()
            else:
                cls.app = QApplication([], False)

        @classmethod
        def tearDownClass(cls):
            del cls.app

        def setUp( self ):
            self.layerstack = LayerStackModel()
            self.sims = StackedImageSources( self.layerstack )

            self.g = Graph()
            self.op = OpLazy(self.g)
            self.ds = LazyflowSource( self.op.Output )

            self.ss = SliceSource( self.ds, projectionAlongTZC )

            self.layer = GrayscaleLayer(self.ds)
            self.layerstack.append(self.layer)
            self.ims = imsfac.createImageSource( self.layer, [self.ss] )
            self.sims.register(self.layer, self.ims)

            self.scene = ImageScene2D(PositionModel(), (0,0,0), preemptive_fetch_number=0)
            self.scene.setCacheSize(1)

            self.scene.stackedImageSources = self.sims
            self.scene.dataShape = (30,30)

        def tearDown( self ):
            if self.scene._tileProvider:
                self.scene._tileProvider.notifyThreadsToStop()
                self.scene._tileProvider.joinThreads()

        def renderScene( self, s, exportFilename=None, joinRendering=True):
            img = QImage(30,30,QImage.Format_ARGB32_Premultiplied)
            img.fill(Qt.white)
            p = QPainter(img)

            s.render(p) #trigger a rendering of the whole scene
            if joinRendering:
                #wait for all the data to arrive
                s.joinRendering()
                #finally, render everything
                s.render(p)
            p.end()

            if exportFilename is not None:
                img.save(exportFilename)
            return byte_view(img)

        def testLazy( self ):
            for i in range(3):
                self.op.setConstant(i)
                aimg = self.renderScene(self.scene, "/tmp/a_%03d.png" % i)
                assert numpy.all(aimg[:,:,0] == i), "!= %d, [0,0,0]=%d" % (i, aimg[0,0,0])

                self.op.setConstant(42)
                self.op.setDelay(1)
                aimg = self.renderScene(self.scene, joinRendering=False, exportFilename="/tmp/x_%03d.png" % i)
                #this should be "i", not 255 (the default background for the imagescene)
                assert numpy.all(aimg[:,:,0] == i), "!= %d, [0,0,0]=%d" % (i, aimg[0,0,0])
コード例 #47
0
ファイル: tiling_tests.py プロジェクト: skarale25/volumina
class DirtyPropagationTest( ut.TestCase ):

    def setUp( self ):
        dataShape = (1, 900, 400, 10, 1) # t,x,y,z,c
        data = np.indices(dataShape)[3].astype(np.uint8) # Data is labeled according to z-index
        self.ds1 = ArraySource( data )
        self.CONSTANT = 13
        self.ds2 = ConstantSource( self.CONSTANT )

        self.layer1 = GrayscaleLayer( self.ds1, normalize=False )
        self.layer1.visible = True
        self.layer1.opacity = 1.0

        self.layer2 = GrayscaleLayer( self.ds2, normalize=False )

        self.lsm = LayerStackModel()
        self.pump = ImagePump( self.lsm, SliceProjection(), sync_along=(0,1,2) )

    def testEverythingDirtyPropagation( self ):
        self.lsm.append(self.layer2)
        tiling = Tiling((900,400), blockSize=100)
        tp = TileProvider(tiling, self.pump.stackedImageSources)

        tp.requestRefresh(QRectF(100,100,200,200))
        tp.waitForTiles()
        tiles = tp.getTiles(QRectF(100,100,200,200))
        for tile in tiles:
            aimg = byte_view(tile.qimg)
            self.assertTrue(np.all(aimg[:,:,0:3] == self.CONSTANT))
            self.assertTrue(np.all(aimg[:,:,3] == 255))

        NEW_CONSTANT = self.CONSTANT+1
        self.ds2.constant = NEW_CONSTANT
        tp.requestRefresh(QRectF(100,100,200,200))
        tp.waitForTiles()
        tiles = tp.getTiles(QRectF(100,100,200,200))
        for tile in tiles:
            aimg = byte_view(tile.qimg)
            self.assertTrue(np.all(aimg[:,:,0:3] == NEW_CONSTANT))
            self.assertTrue(np.all(aimg[:,:,3] == 255))

    def testOutOfViewDirtyPropagation( self ):
        self.lsm.append(self.layer1)
        tiling = Tiling((900,400), blockSize=100)
        tp = TileProvider(tiling, self.pump.stackedImageSources)

        # Navigate down to the second z-slice
        self.pump.syncedSliceSources.through = [0,1,0]
        tp.requestRefresh(QRectF(100,100,200,200))
        tp.waitForTiles()

        # Sanity check: Do we see the right data on the second
        # slice? (should be all 1s)
        tiles = tp.getTiles(QRectF(100,100,200,200))
        for tile in tiles:
            aimg = byte_view(tile.qimg)
            self.assertTrue(np.all(aimg[:,:,0:3] == 1))
            self.assertTrue(np.all(aimg[:,:,3] == 255))

        # Navigate down to the third z-slice
        self.pump.syncedSliceSources.through = [0,2,0]
        tp.requestRefresh(QRectF(100,100,200,200))
        tp.waitForTiles()

        # Sanity check: Do we see the right data on the third
        # slice?(should be all 2s)
        tiles = tp.getTiles(QRectF(100,100,200,200))
        for tile in tiles:
            aimg = byte_view(tile.qimg)
            self.assertTrue(np.all(aimg[:,:,0:3] == 2))
            self.assertTrue(np.all(aimg[:,:,3] == 255))

        # Navigate back up to the second z-slice
        self.pump.syncedSliceSources.through = [0,1,0]
        tp.requestRefresh(QRectF(100,100,200,200))
        tp.waitForTiles()
        for tile in tiles:
            aimg = byte_view(tile.qimg)
            self.assertTrue(np.all(aimg[:,:,0:3] == 1))
            self.assertTrue(np.all(aimg[:,:,3] == 255))

        # Change some of the data in the (out-of-view) third z-slice
        slicing = (slice(None), slice(100,300), slice(100,300),
                   slice(2,3), slice(None))
        slicing = tuple(slicing)
        self.ds1._array[slicing] = 99
        self.ds1.setDirty( slicing )

        # Navigate back down to the third z-slice
        self.pump.syncedSliceSources.through = [0,2,0]
        tp.requestRefresh(QRectF(100,100,200,200))
        tp.waitForTiles()

        # Even though the data was out-of-view when it was
        # changed, it should still have new values. If dirtiness
        # wasn't propagated correctly, the cache's old values will
        # be used. (For example, this fails if you comment out the
        # call to setDirty, above.)

        # Shrink accessed rect by 1 pixel on each side (Otherwise,
        # tiling overlap_draw causes getTiles() to return
        # surrounding tiles that we haven't actually touched in
        # this test)
        tiles = tp.getTiles(QRectF(101,101,198,198))

        for tile in tiles:
            aimg = byte_view(tile.qimg)
            # Use any() because the tile borders may not be
            # perfectly aligned with the data we changed.
            self.assertTrue(np.any(aimg[:,:,0:3] == 99))
コード例 #48
0
class ImageScene2D_RenderTest(ut.TestCase):
    @classmethod
    def setUpClass(cls):
        cls.app = None
        if QApplication.instance():
            cls.app = QApplication.instance()
        else:
            cls.app = QApplication([], False)

    @classmethod
    def tearDownClass(cls):
        del cls.app

    def setUp(self):
        self.layerstack = LayerStackModel()
        self.sims = StackedImageSources(self.layerstack)

        self.GRAY = 201
        self.ds = ConstantSource(self.GRAY)
        self.layer = GrayscaleLayer(self.ds)
        self.layerstack.append(self.layer)
        self.ims = imsfac.createImageSource(self.layer, [self.ds])
        self.sims.register(self.layer, self.ims)

        self.scene = ImageScene2D(PositionModel(), (0, 3, 4),
                                  preemptive_fetch_number=0)

        self.scene.stackedImageSources = self.sims
        self.scene.dataShape = (310, 290)

    def tearDown(self):
        if self.scene._tileProvider:
            self.scene._tileProvider.notifyThreadsToStop()
            self.scene._tileProvider.joinThreads()

    def renderScene(self, s, exportFilename=None):
        img = QImage(310, 290, QImage.Format_ARGB32_Premultiplied)
        img.fill(0)
        p = QPainter(img)
        s.render(p)
        s.joinRendering()
        s.render(p)
        p.end()
        if exportFilename is not None:
            img.save(exportFilename)
        return byte_view(img)

    def testBasicImageRenderingCapability(self):
        aimg = self.renderScene(self.scene)
        self.assertTrue(np.all(aimg[:, :, 0:3] == self.GRAY))
        self.assertTrue(np.all(aimg[:, :, 3] == 255))

    def testToggleVisibilityOfOneLayer(self):
        aimg = self.renderScene(self.scene)
        self.assertTrue(np.all(aimg[:, :, 0:3] == self.GRAY))
        self.assertTrue(np.all(aimg[:, :, 3] == 255))

        self.layer.visible = False
        aimg = self.renderScene(self.scene)
        self.assertTrue(np.all(aimg[:, :, 0:3] == 0))  # all white
        self.assertTrue(np.all(aimg[:, :, 3] == 0))

        self.layer.visible = True
        aimg = self.renderScene(self.scene)
        self.assertTrue(np.all(aimg[:, :, 0:3] == self.GRAY))
        self.assertTrue(np.all(aimg[:, :, 3] == 255))
コード例 #49
0
ファイル: layerwidget_test.py プロジェクト: JensNRAD/volumina
class TestLayerWidget( ut.TestCase ):
    """
    Create two layers and add them to a LayerWidget.
    Then change one of the layer visibilities and verify that the layer widget appearance updates.
    
    At the time of this writing, the widget doesn't properly repaint the selected layer (all others repaint correctly).
    """
    
    @classmethod
    def setUpClass(cls):
        if 'TRAVIS' in os.environ:
            # This test fails on Travis-CI for unknown reasons,
            #  probably due to the variability of time.sleep().
            # Skip it on Travis-CI.
            import nose
            raise nose.SkipTest

        cls.app = QApplication([])
        cls.errors = False

    @classmethod
    def tearDownClass(cls):
        del cls.app
    
    def impl(self):
        try:
            # Capture the window before we change anything
            beforeImg = QPixmap.grabWindow( self.w.winId() ).toImage()
            
            # Change the visibility of the *selected* layer
            self.o2.visible = False
            
            self.w.repaint()
            
            # Make sure the GUI is caught up on paint events
            QApplication.processEvents()
            
            # We must sleep for the screenshot to be right.
            time.sleep(0.1) 

            # Capture the window now that we've changed a layer.
            afterImg = QPixmap.grabWindow( self.w.winId() ).toImage()
    
            # Optional: Save the files so we can inspect them ourselves...
            #beforeImg.save('before.png')
            #afterImg.save('after.png')

            # Before and after should NOT match.
            assert beforeImg != afterImg
        except:
            # Catch all exceptions and print them
            # We must finish so we can quit the app.
            import traceback
            traceback.print_exc()
            TestLayerWidget.errors = True

        qApp.quit()

    def test_repaint_after_visible_change(self):
        self.model = LayerStackModel()

        self.o1 = Layer([])
        self.o1.name = "Fancy Layer"
        self.o1.opacity = 0.5
        self.model.append(self.o1)
        
        self.o2 = Layer([])
        self.o2.name = "Some other Layer"
        self.o2.opacity = 0.25
        self.model.append(self.o2)
        
        self.view = LayerWidget(None, self.model)
        self.view.show()
        self.view.updateGeometry()
    
        self.w = QWidget()
        self.lh = QHBoxLayout(self.w)
        self.lh.addWidget(self.view)
        self.w.setGeometry(100, 100, 300, 300)
        self.w.show()

        # Run the test within the GUI event loop
        QTimer.singleShot(500, self.impl )
        self.app.exec_()
        
        # Were there errors?
        assert not TestLayerWidget.errors, "There were GUI errors/failures.  See above."        
コード例 #50
0
ファイル: viewer.py プロジェクト: christophdecker/volumina
class Viewer(QMainWindow):
    """High-level API to view multi-dimensional arrays.

    Properties:
        title -- window title

    """
    def __init__(self, parent=None):
        QMainWindow.__init__(self, parent)
        uiDirectory = os.path.split(volumina.__file__)[0]
        if uiDirectory == '':
            uiDirectory = '.'
        loadUi(uiDirectory + '/viewer.ui', self)

        self._dataShape = None
        self._viewerInitialized = False
        self.editor = None
        self.viewingWidget = None
        self.actionQuit.triggered.connect(qApp.quit)

        #when connecting in renderScreenshot to a partial(...) function,
        #we need to remember the created function to be able to disconnect
        #to it later
        self._renderScreenshotDisconnect = None

        self.initLayerstackModel()

        self.actionCurrentView = QAction(QIcon(), "Only for selected view",
                                         self.menuView)
        f = self.actionCurrentView.font()
        f.setBold(True)
        self.actionCurrentView.setFont(f)

        # Lazy import here to prevent this module from ignoring volumine.NO3D flag.
        from volumina.volumeEditor import VolumeEditor
        self.editor = VolumeEditor(self.layerstack, parent=self)

        #make sure the layer stack widget, which is the right widget
        #managed by the splitter self.splitter shows up correctly
        #TODO: find a proper way of doing this within the designer
        def adjustSplitter():
            s = self.splitter.sizes()
            s = [int(0.66 * s[0]), s[0] - int(0.66 * s[0])]
            self.splitter.setSizes(s)

        QTimer.singleShot(0, adjustSplitter)

    @property
    def title(self):
        return self.windowTitle()

    @title.setter
    def title(self, t):
        self.setWindowTitle(t)

    def initLayerstackModel(self):
        self.layerstack = LayerStackModel()
        self.layerWidget.init(self.layerstack)
        model = self.layerstack
        self.UpButton.clicked.connect(model.moveSelectedUp)
        model.canMoveSelectedUp.connect(self.UpButton.setEnabled)
        self.DownButton.clicked.connect(model.moveSelectedDown)
        model.canMoveSelectedDown.connect(self.DownButton.setEnabled)
        self.DeleteButton.clicked.connect(model.deleteSelected)
        model.canDeleteSelected.connect(self.DeleteButton.setEnabled)

    @property
    def dataShape(self):
        return self._dataShape

    @dataShape.setter
    def dataShape(self, s):
        if s is None:
            return
        assert len(s) == 5

        self._dataShape = s
        self.editor.dataShape = s
        if not self._viewerInitialized:
            self._viewerInitialized = True
            self.viewer.init(self.editor)
            #make sure the data shape is correctly set
            #(some signal/slot connections may be set up in the above init)
            self.editor.dataShape = s

            #FIXME: this code is broken
            #if its 2D, maximize the corresponding window
            #if len([i for i in list(self.dataShape)[1:4] if i == 1]) == 1:
            #    viewAxis = [i for i in range(1,4) if self.dataShape[i] == 1][0] - 1
            #    self.viewer.quadview.switchMinMax(viewAxis)

    def addGrayscaleLayer(self, a, name=None, direct=False):
        source, self.dataShape = createDataSource(a, True)
        layer = GrayscaleLayer(source, direct=direct)
        layer.numberOfChannels = self.dataShape[-1]
        if name:
            layer.name = name
        self.layerstack.append(layer)
        return layer

    def addAlphaModulatedLayer(self, a, name=None):
        source, self.dataShape = createDataSource(a, True)
        layer = AlphaModulatedLayer(source)
        if name:
            layer.name = name
        self.layerstack.append(layer)
        return layer

    def addRGBALayer(self, a, name=None):
        assert a.shape[2] >= 3
        sources = [None, None, None, None]
        for i in range(3):
            sources[i], self.dataShape = createDataSource(a[..., i], True)
        if (a.shape[-1] >= 4):
            sources[3], self.dataShape = createDataSource(a[..., 3], True)
        layer = RGBALayer(sources[0], sources[1], sources[2], sources[3])
        if name:
            layer.name = name
        self.layerstack.append(layer)
        return layer

    def addRandomColorsLayer(self, a, name=None, direct=False):
        layer = self.addColorTableLayer(a,
                                        name,
                                        colortable=None,
                                        direct=direct)
        layer.colortableIsRandom = True
        layer.zeroIsTransparent = True
        return layer

    def addColorTableLayer(self,
                           a,
                           name=None,
                           colortable=None,
                           direct=False,
                           clickFunctor=None):
        if colortable is None:
            colortable = self._randomColors()
        source, self.dataShape = createDataSource(a, True)
        if clickFunctor is None:
            layer = ColortableLayer(source, colortable, direct=direct)
        else:
            layer = ClickableColortableLayer(self.editor,
                                             clickFunctor,
                                             source,
                                             colortable,
                                             direct=direct)
        if name:
            layer.name = name
        self.layerstack.append(layer)
        return layer

    def addRelabelingColorTableLayer(self,
                                     a,
                                     name=None,
                                     relabeling=None,
                                     colortable=None,
                                     direct=False,
                                     clickFunctor=None,
                                     right=True):
        if colortable is None:
            colortable = self._randomColors()
        source = RelabelingArraySource(a)
        if relabeling is None:
            source.setRelabeling(numpy.zeros(numpy.max(a) + 1, dtype=a.dtype))
        else:
            source.setRelabeling(relabeling)
        if colortable is None:
            colortable = [QColor(0, 0, 0, 0).rgba(), QColor(255, 0, 0).rgba()]
        if clickFunctor is None:
            layer = ColortableLayer(source, colortable, direct=direct)
        else:
            layer = ClickableColortableLayer(self.editor,
                                             clickFunctor,
                                             source,
                                             colortable,
                                             direct=direct,
                                             right=right)
        if name:
            layer.name = name
        self.layerstack.append(layer)
        return (layer, source)

    def addClickableSegmentationLayer(self,
                                      a,
                                      name=None,
                                      direct=False,
                                      colortable=None,
                                      reuseColors=True):
        return ClickableSegmentationLayer(a,
                                          self,
                                          name=name,
                                          direct=direct,
                                          colortable=colortable,
                                          reuseColors=reuseColors)

    def _randomColors(self, M=256):
        """Generates a pleasing color table with M entries."""

        colors = []
        for i in range(M):
            if i == 0:
                colors.append(QColor(0, 0, 0, 0).rgba())
            else:
                h, s, v = random.random(), random.random(), 1.0
                color = numpy.asarray(colorsys.hsv_to_rgb(h, s, v)) * 255
                qColor = QColor(*color)
                colors.append(qColor.rgba())
        #for the first 16 objects, use some colors that are easily distinguishable
        colors[1:17] = colortables.default16
        return colors