0

I have raster images reporting the start day and end day of some periods across the globe. For each pixel (read numpy array element) I'd like to get a measure of how much its day-unit period overlap/intersect with that of the neighboring pixels. Formally, I want to obtain:

Xp = Σk∈Np | Tp ∩ Tk|

where: Tp = {Sp , Sp + 1, ..., Ep} is the period in pixel p and Np is the set identifying the neighbor of pixel p.

I've tried to compute my measure using a custom function in scipy.ndimage.generic_filter(). My first approach was to work directly with an array reporting Tp sets; this didn't work because I think that the generic_filter() function does not accept arrays with sets (I got RuntimeError: array type not supported).
I have thus tried to work with a custom function that: (i) has the two arrays for period start and end as inputs, (ii) builds the T sets and (iii) computes their intersection. However, I don't know how to pass it correctly into the generic_filter(). Below is my code:

import numpy as np
import scipy.ndimage as ndimage

# Preliminaries
def calendar(s,e):    # build the T array
    return set(range(s, e))
vect_calendar = np.vectorize(calendar)

s = np.array([[99, 99, 1], [2, 2, 4], [1, 99, 99], [99, 3, 3]]) # start day of T (99=missing day)
e = np.array([[0, 0, 3], [6, 4, 7], [3, 0, 0], [0, 4, 5]])
t = vect_calendar(s,e)
x_expected = np.array([[0, 0, 2], [6, 4, 2], [2, 0, 0], [0, 1, 1]])

# Function for computing intersection across pixels (note I exclude the central pixel from computations)
ns = 9
ray = int((ns**(1/2)-1)/2)

def neig_func(arr_s, arr_e):
    p = int((ns-1)/2)  # central pixel of the neighborhood
    t_p = set(range(int(arr_s[p]), int(arr_e[p])))
    
    agg = []
    for k in range(ns):
        t_k = set(range(int(arr_s[k]), int(arr_e[k])))
        f_pk = set.intersection(t_p, t_k)
        f_pk = len(f_pk)
        agg.append(f_pk)
    return np.sum(agg) - len(t_p)

# Run the function across all pixel neighbors except those on the top & bottom edges of the array
s_bord = np.pad(s, pad_width=((ray,ray),(0,0)), mode="constant", constant_values=0)
e_bord = np.pad(e, pad_width=((ray,ray),(0,0)), mode="constant", constant_values=0)
e_bord_flat = e_bord.flatten()

neig = np.ones((int(ns**(1/2)), int(ns**(1/2))))
x = ndimage.generic_filter(s_bord, neig_func, footprint=neig, mode="wrap", extra_arguments=(e_bord_flat,))
print("Input data is: \n", t, "\n\n****\n Expected output is: \n", x_expected, "\n\n****\n Actual output is \n", x[ns:-ns])

The output is an array with all zeros! I guess that the problem is that the array e is read by the generic_filter() always in its first ns elements.
An alternative solution could be have a 3-d array with s and e stacked one over the other. Yet, it seems that I can't run the generic_filter() on 3-dimensional arrays.

Matteo
  • 1
  • 1

0 Answers0