Search code examples
cython

Cython: declaring a variable window during looping over an array


I'm trying to loop over a 3D array with a window. At each iteration, the window is moved 1 pixel and the variance for the (3D)window is calculated.

I'm trying to do this in Cython for performance reasons, in Jupyter notebook.

My (working, but slow) code in python looks approximately like this:

## PYTHON
#code adapted from https://stackoverflow.com/questions/36353262/i-need-a-fast-way-to-loop-through-pixels-of-an-image-stack-in-python
def Variance_Filter_3D_python(image, kernel = 30):
  
    min_var = 10000
    min_var_coord = [0,0,0]
    
    window = np.zeros(shape=(kernel,kernel,kernel), dtype = np.uint8)
    z,y,x = image.shape
    
    for i in np.arange(0,(z-kernel),1):
        for j in np.arange(0,(y-kernel),1):
            for k in np.arange(0,(x-kernel),1):
                window[:,:,:] = image[i:i+kernel,j:j+kernel,k:k+kernel]
                var = np.var(window)
                if var < min_var:
                    min_var = var
                    min_var_coord = [i,j,k]
                print(min_var_coord)
    return min_var,min_var_coord

When I try to declare the variables in the cython code:

%%cython

@cython.boundscheck(False)  # Deactivate bounds checking
@cython.wraparound(False)
def Variance_Filter_3D(image, kernel = 30):
    cdef double min_var = 10000
    cdef list min_var_coord = [0,0,0] 
    cdef unsigned int z,y,x = image.shape
    cdef np.ndarray[float, ndim=3] window = np.zeros(shape=(kernel,kernel,kernel), 
    dtype=FTYPE)

....etc

I get a error saying that "'np' is not declared" in the following line:

 cdef np.ndarray[float, ndim=3] window = np.zeros(shape=(kernel,kernel,kernel), 
    dtype=FTYPE)

and that cython isn't declared in these lines:

@cython.boundscheck(False)  # Deactivate bounds checking
@cython.wraparound(False)

However, I have used cimport previously:

%%cython
cimport numpy as np
cimport cython

What's going wrong?


Solution

  • You probably need to put the Numpy and Cython cimports in the exact notebook cell you need them in. Cython doesn't have a lot of "global scope" in Jupiter.

    However,

    window[:,:,:] = image[i:i+kernel,j:j+kernel,k:k+kernel]
    

    will work a lot better if:

    1. you set the type of image to be a memoryview. Slicing a memoryview is fairly quick while viewing an arbitrary Python object as a memoryview is slower.
    2. You made the left-hand side window instead of window[:,:,:] (a view rather than a copy)