Skuteczne obliczanie średniej sąsiedztwa dostosowanej do granic

Mam obraz o wartościach od 0 do 1. To, co lubię robić, to proste uśrednianie.
Ale dokładniej, dla komórki na granicy obrazu chciałbym obliczyć średnią pikseli dla tej części sąsiedztwa / jądra, która leży w zasięgu obrazu. W rzeczywistości sprowadza się to do dostosowania mianownika „średniej formuły”, liczby pikseli podzielonych przez sumę.

Udało mi się to zrobić, jak pokazano poniżejscipy.ndimage.generic_filter, ale to jest dalekie od czasu.

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})

Detale

kernel = kwadratowa tablica (okrąg reprezentowany przez jedynki)Dopełnianie zerami, a nie zerami, od tego czasu nie mogłem poprawnie oddzielić zer obszaru wypełnionego i zer rzeczywistego rastracountkernel = liczba tych wkerneln = liczba komórek, które leżą wewnątrzimage wykluczając komórki obszaru wypełnionego identyfikowane przez wartości 2Poprawsum odejmując (liczbę wyściełanych komórek * 2,0) od sumy początkowej sąsiedztwa

Aktualizacje

1) Wypełnienie NaNs zwiększa obliczenia o około 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) Zastosowanie rozwiązania zaproponowanego przezYves Daoust (zaakceptowana odpowiedź), zdecydowanie skraca czas przetwarzania do minimum:

    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) W oparciu oYves ' wskazówka, aby użyć dodatkowego obrazu binarnego, który w rzeczywistości stosuje maskę, natknąłem się na zasadęzamaskowane tablice. Tylko jedna tablica musi być przetworzona, ponieważ zamaskowana tablica „łączy” tablicę obrazu i maski razem.
Niewielki szczegół dotyczący tablicy maski: zamiast wypełniać wewnętrzną część (zakres oryginalnego obrazu) za pomocą 1 i wypełniając zewnętrzną część (obramowanie) za pomocą 0, tak jak w poprzedniej aktualizacji, musisz zrobić odwrotnie. 1 w maskowanej tablicy oznacza „nieprawidłowy”, 0 oznacza „ważny”.
Ten kod jest nawet o 50% szybszy niż kod podany w aktualizacji 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)

-> Muszę się poprawić tutaj!
Muszę się mylić podczas walidacji, ponieważ po kilku obliczeniach wydawało się, że takscipy.ndimage.<filters> nie może obsłużyć maskowanych_rar w tym sensie, że podczas operacji filtrowania maska ​​nie jest brana pod uwagę.
Mówili o tym również inni ludzietutaj itutaj.

Moc obrazu ...

szary: zakres przetwarzanego obrazubiały: obszar wyściełany (w moim przypadku wypełniony 2.0)czerwone odcienie: zakres jądraciemnoczerwony: skuteczny sąsiadjasnoczerwony: część sąsiedztwa należy zignorować

Jak można zmienić ten raczej pragmatyczny fragment kodu, aby poprawić wydajność obliczeń?

Z góry bardzo dziękuję!

questionAnswers(2)

yourAnswerToTheQuestion