class PlanarSliceSourceTest(ut.TestCase): def setUp(self): self.raw = np.random.randint(0, 100, (10, 3, 3, 128, 3)) self.a = ArraySource(self.raw) self.ss = PlanarSliceSource(self.a, projectionAlongTZC) def testRequest(self): self.ss.setThrough(0, 1) self.ss.setThrough(2, 2) self.ss.setThrough(1, 127) sl = self.ss.request((slice(None), slice(None))).wait() self.assertTrue(np.all(sl == self.raw[1, :, :, 127, 2])) sl_bounded = self.ss.request((slice(0, 3), slice(1, None))).wait() numpy.testing.assert_array_equal(sl_bounded, self.raw[1, 0:3, 1:, 127, 2]) def testDirtynessPropagation(self): self.ss.setThrough(0, 1) self.ss.setThrough(2, 2) self.ss.setThrough(1, 127) check_mock = mock.Mock() self.ss.isDirty.connect(check_mock) self.a.setDirty(np.s_[1:2, :, 1:2, 127:128, 2:3]) self.ss.isDirty.disconnect(check_mock) check_mock.assert_called_once_with(np.s_[:, 1:2])
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))
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()