Cálculo eficiente del promedio de vecindad adaptado a los límites.

Tengo una imagen con valores que van de 0 a 1. Lo que me gusta hacer es un promedio simple.
Pero, más específicamente, para una celda en el borde de la imagen, me gustaría calcular el promedio de los píxeles para esa parte del vecindario / núcleo que se encuentra dentro de la extensión de la imagen. De hecho, esto se reduce a adaptar el denominador de la 'fórmula de la media', el número de píxeles por los que se divide la suma.

Logré hacer esto como se muestra a continuación conscipy.ndimage.generic_filter, pero esto está lejos de ser eficiente en el tiempo.

def fnc(buffer, count):
    n = float(sum(buffer < 2.0))
    sum = sum(buffer) - ((count - b) * 2.0)
    return (sum / n)

avg = scipy.ndimage.generic_filter(image, fnc, footprint = kernel, \
                                   mode = 'constant', cval = 2.0,   \
                                   extra_keywords = {'count': countkernel})

Detalles

kernel = matriz cuadrada (círculo representado por unos)Relleno con 2 y no con ceros desde entonces no pude separar correctamente los ceros del área rellenada y los ceros del ráster realcountkernel = número de unos en elkerneln = número de celdas que se encuentran dentroimage Al excluir las celdas del área de relleno identificadas por valores de 2Corrige elsum restando (número de celdas rellenadas * 2.0) de la suma total de vecindad original

Actualización (s)

1) El relleno con NaN aumenta el cálculo en aproximadamente un 30%:

    def fnc(buffer):
        return (numpy.nansum(buffer) / numpy.sum([~numpy.isnan(buffer)]))

    avg = scipy.ndimage.generic_filter(image, fnc, footprint = kernel, \
                                       mode = 'constant', cval = float(numpy.nan)

2) Aplicando la solución propuesta porYves Daoust (respuesta aceptada), definitivamente reduce el tiempo de procesamiento a un mínimo:

    def fnc(buffer):
        return numpy.sum(buffer)

    sumbigimage = scipy.ndimage.generic_filter(image, fnc, \
                                               footprint = kernel, \
                                               mode = 'constant', \
                                               cval = 0.0)
    summask     = scipy.ndimage.generic_filter(mask, fnc, \
                                               footprint = kernel, \
                                               mode = 'constant', \
                                               cval = 0.0)
    avg = sumbigimage / summask

3) Sobre la base deYves Sugerencia para usar una imagen binaria adicional, que de hecho está aplicando una máscara, me topé con el principio dematrices enmascaradas. Como tal, solo se debe procesar una matriz porque una matriz enmascarada "combina" la imagen y las matrices de máscara.
Un pequeño detalle sobre la matriz de la máscara: en lugar de llenar la parte interior (extensión de la imagen original) con 1 y completar la parte exterior (borde) con 0 como se hizo en la actualización anterior, debe hacerlo al revés. Un 1 en una matriz enmascarada significa "no válido", un 0 significa "válido".
Este código es incluso un 50% más rápido que el código suministrado en la actualización 2):

    maskedimg = numpy.ma.masked_array(imgarray, mask = maskarray)

    def fnc(buffer):
        return numpy.mean(buffer)

    avg = scipy.ndimage.generic_filter(maskedimg, fnc, footprint = kernel, \
                                       mode = 'constant', cval = 0.0)

-> Debo corregirme aquí!
Debo estar equivocado durante la validación, ya que después de algunos cálculos, parecía quescipy.ndimage.<filters> no puede manejar masked_arrays en ese sentido que durante la operación de filtro la máscara no se tiene en cuenta.
Algunas otras personas mencionaron esto también, comoaquí yaquí.

El poder de una imagen ...

gris: extensión de la imagen a procesarblanco: área acolchada (en mi caso llena de 2.0)Tonos rojos: extensión del grano.rojo oscuro: barrio efectivorojo claro: parte del barrio que debe ser ignorado

¿Cómo se puede cambiar esta pieza de código más bien pragmática para mejorar el rendimiento del cálculo?

¡Muchas gracias de antemano!

Respuestas a la pregunta(2)

Su respuesta a la pregunta