What is the right way to update a big image in napari

I follow the interactive_scripting.py demo, and modify it to measure the fps to update a 10240x10240 image. and the fps is very slow (1 fps). I want to build a real time label tool. (such as ilastik), may be I did not use it in the right way. So what is the right way to update big image?

import numpy as np
import napari
import time

with napari.gui_qt():
    # create the viewer with an image
    data = np.random.random((2, 10240, 10240))
    viewer = napari.Viewer()
    layer = viewer.add_image(data[1])

    def layer_update(*, update_period, num_updates):
        # number of times to update
        t = time.time()
        for k in range(num_updates):
            layer.data = data[k%2]

            # check that data layer is properly assigned and not blocked?
            while layer.data.all() != data[k%2].all():
                layer.data = data[k%2]
            print(round(1/(time.time()-t), 2))
            t = time.time()

    viewer.update(layer_update, update_period=0.0, num_updates=10)

the result is about 1fps.

Hi @yxdragon - that is the preferred way to assign data to a layer in napari, and sorry it’s not fast enough for you right now.

I’ve got a couple comments about the way things are now / some minor things you can do now, and also link to some work that we have in progress, including discussions around a more lazy, non-blocking rendering scheme that you might be interested in.

First off, right now we are auto-computing image pyramids if data is bigger than 8092 in an axis, we will change this behaviour in an upcoming release, see here for some general discussion https://github.com/napari/napari/issues/736. In the mean time you should probably use

layer = viewer.add_image(data[1], is_pyramid=False)

to avoid those calculations, though at a certain definition of “big” pyramids will be needed.

Some speed up can be obtained from just setting the view data directly (and avoiding things like slicing and thumbnail generation), by doing the following, but I think we want to avoid that as a long term solution, or maybe provide a simpler way to at least turn off thumbnail generation

layer._data_view = data[k%2]
layer.events.set_data()

Even then, it doesn’t make things go much faster.

Your check

layer.data.all() != data[k%2].all()

alone is > 150ms which means this code would never run > 6 fps for such a large image if I am not mistaken, and dropping the check takes me to around 3 fps including thumbnail generation etc.

We are currently exploring a more lazy rendering scheme - see here https://github.com/napari/napari/issues/318 and other issues for discussion - which would allow for assignment in a non-blocking way.

If all you are interested in though is ilastik style labeling, napari supports a labels layer with a paintbrush - see here for more info https://napari.org/tutorials/labels. Right now painting will still be too slow for 10240x10240 image, but we are adding a new shader to make it much faster - see this PR here https://github.com/napari/napari/pull/713

1 Like