Image filtering using cupy#

Cupy also comes with drop-in replacements for scipy’s ndimage submodule called cupyx.scipy.ndimage. It allows us to call common functions such as gaussian_filter() with identical parameters.

For importing this submodule, we use again a failsafe pattern:

try:
    import cupy as xp
except:
    import numpy as xp

import numpy as np

try:
    import cupyx.scipy.ndimage as xdi
except:
    import scipy.ndimage as xdi

import scipy.ndimage as ndi
    
xdi
<module 'cupyx.scipy.ndimage' from 'C:\\Users\\haase\\mambaforge\\envs\\cupy39_1\\lib\\site-packages\\cupyx\\scipy\\ndimage\\__init__.py'>
from skimage.io import imread, imshow
from timeit import timeit
import stackview
image = imread("../../data/blobs.tif")

xp_image = xp.asarray(image)

type(xp_image)
cupy.ndarray

We can then use the xdi alias to call the gaussian_filter() function without worrying if cupy is installed or not.

xp_blurred = xdi.gaussian_filter(xp_image, sigma=5)

Before we can show the image, we must transfer it back to CPU memory and convert it to a numpy array.

stackview.insight(xp_blurred)
shape(254, 256)
dtypeuint8
size63.5 kB
min35
max237

Quick-and-dirty benchmarking#

To get a rough idea about potential speedup using cupy, one can use the timeit jupyter magic.

%%timeit
xdi.gaussian_filter(xp_image, sigma=5)
228 µs ± 8.87 µs per loop (mean ± std. dev. of 7 runs, 1,000 loops each)
%%timeit
xp_image = xp.asarray(image)
xdi.gaussian_filter(xp_image, sigma=5)
305 µs ± 9.88 µs per loop (mean ± std. dev. of 7 runs, 1,000 loops each)
%%timeit
ndi.gaussian_filter(image, sigma=5)
1.39 ms ± 22.8 µs per loop (mean ± std. dev. of 7 runs, 1,000 loops each)

Exercises#

Explore which other filters are available in cupy, and which not. Use the documentation: https://docs.cupy.dev/en/stable/reference/scipy_ndimage.html