Гауссовская фильтрация изображения с помощью Nan в Python

Из списка 2D-координат и третьей переменной (скорости) я создал массив 2D numpy, охватывающий всю область выборки. Я намерен создать изображение, в котором каждый пиксель содержит среднюю скорость лежащих в нем точек. После этого фильтруйте это изображение с помощью гауссовского фильтра.

Проблема заключается в том, что область неравномерно отбирается. Поэтому у меня есть несколько пикселей без информации (Nan) в середине изображения. Когда я пытаюсь фильтровать массив через гауссовский фильтр, Nan распространяется, разрушая все изображение.

Мне нужно отфильтровать это изображение, но отбросить все пиксели без информации. Другими словами, если пиксель не содержит информации, он не должен учитываться для фильтрации.

Вот пример моего кода для усреднения:

Mean_V = np.zeros([len(x_bins), len(y_bins)])

for i, x_bin in enumerate(x_bins[:-1]):
    bin_x = (x > x_bins[i]) & (x <= x_bins[i+1])
    for j, y_bin in enumerate(y_bins[:-1]):
        bin_xy = (y[bin_x] > y_bins[j]) & (y[bin_x] <= y_bins[j+1])
        if (sum(x > 0 for x in bin_xy) > 0) :
            Mean_V[i,j]=np.mean(V[bin_x][bin_xy])
        else:
            Mean_V[i,j]=np.nan

EDIT:

Серфинг в Интернете Я закончил этот вопрос, который я сделал в 2013 году. Решение этой проблемы можно найти в библиотеке астрофизики:

http://docs.astropy.org/en/stable/convolution/

Астропическая свертка заменяет пиксели NaN взвешенной по ядру интерполяцией от их соседей.

Спасибо, ребята!

Ответ 1

в словах:

Гауссовский фильтр, который игнорирует NaN в заданном массиве U, можно легко получить, применив стандартный гауссовский фильтр к двум вспомогательным массивам V и W и взяв их соотношение, чтобы получить результат Z.

Здесь V - копия исходного U с заменой NaN на нули, а W - массив единиц с нулями, указывающий положение NaNs в исходном U.

Идея состоит в том, что замена NaN на нули вводит ошибку в отфильтрованном массиве, который, однако, может быть скомпенсирован путем применения того же гауссовского фильтра к другому вспомогательному массиву и объединения двух.

в Python:

import scipy as sp
import scipy.ndimage

U=sp.randn(10,10)          # random array...
U[U<2]=np.nan              # ...with NaNs for testing

V=U.copy()
V[U!=U]=0
VV=sp.ndimage.gaussian_filter(V,sigma=2.0)

W=0*U.copy()+1
W[U!=U]=0
WW=sp.ndimage.gaussian_filter(W,sigma=2.0)

Z=VV/WW

в цифрах:

Здесь коэффициенты гауссовского фильтра установлены для [0.25,0.50,0.25] для демонстрационных целей и суммируются до одного 0,25 + 0,50 + 0,25 = 1 без потери общности.

После замены NaN на нули и применения фильтра Гаусса (см. ниже) ясно, что нули вводят ошибку, т.е. из-за "отсутствующих" данных коэффициенты 0,25 + 0,50 = 0,75 не суммируются к одному и, следовательно, недооценивать "истинное" значение.

Однако это можно скомпенсировать, используя второй вспомогательный массив (см. WW ниже), который после фильтрации с тем же гауссовским просто содержит сумму коэффициентов.

Следовательно, разделение двух фильтрованных вспомогательных массивов масштабирует коэффициенты таким образом, что они суммируются до единицы, в то время как позиции NaN игнорируются.

array U         1   2   NaN 1   2    
auxiliary V     1   2   0   1   2    
auxiliary W     1   1   0   1   1
position        a   b   c   d   e

filtered VV_b   = 0.25*V_a  + 0.50*V_b  + 0.25*V_c
                = 0.25*1    + 0.50*2    + 0
                = 1.25

filtered WW_b   = 0.25*W_a  + 0.50*W_b  + 0.25*W_c
                = 0.25*1    + 0.50*1    + 0
                = 0.75

ratio Z         = VV_b / WW_b  
                = (0.25*1 + 0.50*2) / (0.25*1    + 0.50*1)
                = 0.333*1 + 0.666*2
                = 1.666

Ответ 2

Как насчет замены Z = VV/WW на Z = VV/(WW + epsilon) на epsilon = 0.000001, чтобы автоматически обрабатывать случаи без каких-либо замечаний в предыдущем предложении

Ответ 3

Самое простое - превратить nan в нули через nan_to_num. Является ли это значимым или нет, это отдельный вопрос.