I'm working on an image analysis tool with a GUI using Pyqtgraph's ImageView. I am working with some large image stacks, and it takes a while to load them into memory. I was able to make a modified version of the ImageView that uses Dask-Image for lazy loading, however it was very slow whenever making changes (I assume because it didn't cache anything into memory) and I'm not even sure if it made anything better.
Here's some sample code to load a TiffFile into an ImageView.
from pathlib import Path
import dask.array as da
import numpy as np
import pyqtgraph as pg
import zarr
from pyqtgraph.Qt import QtWidgets
from tifffile import TiffFile, imwrite
LAZY = True
if not Path("temp.tiff").exists():
# Generate a sample tiff file for the sake of a self-contained example. Imagine it's
# large though.
data = (np.random.rand(50, 2, 4096, 4096) * 2**16).astype("uint16")
imwrite("temp.tiff", data)
# Custom ImageView
class LazyImageView(pg.ImageView):
def normalize(self, image):
img = super().normalize(image)
if isinstance(img, da.Array):
img = img.compute()
return img
# Interpret image data as row-major instead of col-major
pg.setConfigOptions(imageAxisOrder="row-major")
app = pg.mkQApp("ImageView Example")
## Create window with ImageView widget
win = QtWidgets.QMainWindow()
win.resize(800, 800)
imv = LazyImageView(discreteTimeLine=True)
win.setCentralWidget(imv)
win.show()
win.setWindowTitle("pyqtgraph example: ImageView")
imv.setHistogramLabel("Histogram label goes here")
tif = TiffFile("temp.tiff")
if LAZY:
store = tif.aszarr()
data = da.from_zarr(store)[:, 0, :, :]
else:
store = None
data = tif.asarray()[:, 0, :, :]
# Display the data and assign each frame a time value from 1.0 to 3.0
imv.setImage(data, levelMode="mono")
# Start up with an ROI
imv.ui.roiBtn.setChecked(True)
imv.roiClicked()
if __name__ == "__main__":
pg.exec()
tif.close()
if store is not None:
store.close()
I (think I) want a tool that could be a drop-in replacement that would only load the frame in question into memory. When the data is first accessed, it would then be cached so calculations on that frame would be faster instead of having to re-compute each time. Ideally, if I move to another frame, it will still keep the loaded frame in the background.
Does something like this exist, or does anyone know of a better alternative?