Создать матрицу соседей - PullRequest
0 голосов
/ 28 июня 2018

У меня есть разреженная матрица, и мне нужно создать новую соседнюю матрицу для каждого индекса.

Ниже я оставляю представление данных в матрице NxM. Для каждого из элементов матрицы мне нужно получить соседей в сечении KxK. С этой информацией он сгенерирует матрицу NMxKK, которая содержит в каждой строке индексы соседних KK элемента.

enter image description here

Я задал похожий вопрос некоторое время назад, но разница в том, что теперь данные структурированы, поэтому я могу обойтись без KdTree.

Эта новая матрица используется для расчета расстояния от ненулевых соседей, и с этими расстояниями ассоциируется вес с каждым соседом, чтобы окончательно оценить желаемое значение как средневзвешенное значение соседей. .

Заранее спасибо!

UPDATE

У меня есть данные, подобные изображениям (сгенерированные с помощью функции generate_data), и мне нужно выполнить следующую операцию.

enter image description here

Учитывая матрицу filter / kernel / NxN, где N - размер ядра, определенный мной, для ненулевых значений рассчитайте расстояния по отношению к центральному пикселю. В качестве примера возьмем значение 20, которое находится в положении (1, 8) изображения. Принимая матрицу 5x5, интересующие ненулевые значения равны 40(0, 6)), 37(1, 6)) и 25(3, 10)), с расстояниями 2.23606798, 2 и 2.82842712 соответственно (получено с учетом евклидовой нормы между индексами).

На этом шаге мне нужно получить матрицу res:

[[0.         2.23606798 2.         0.         0.        ]
 [0.         0.         0.         0.         0.        ]
 [0.         0.         1.         0.         0.        ]
 [0.         0.         0.         0.         0.        ]
 [0.         0.         0.         0.         2.82842712]]

Мне нужно также получить 1. в центре матрицы, чтобы также учесть значение, в котором я стою (расстояние до которого 0.).

С этими значениями я получаю маску с ненулевыми значениями и вычисляю веса на основе распределения Гаусса:

import scipy.stats as st 
mask = 0 < res
gauss = st.norm.pdf(res) # or st.norm.pdf(mask * kernel(5))

[[0.        , 0.03274718, 0.05399097, 0.        , 0.        ],
 [0.        , 0.        , 0.        , 0.        , 0.        ],
 [0.        , 0.        , 0.39894228, 0.        , 0.        ],
 [0.        , 0.        , 0.        , 0.        , 0.        ],
 [0.        , 0.        , 0.        , 0.        , 0.00730688]])

total = gauss.sum() # 0.4929873057962355

Наконец, с этими весами я вычисляю вес и окончательное значение пикселя путем интерполяции значений.

val[1, 8] = 0.03274718 * 40 / total + 0.05399097 * 37 / total + 0.39894228 * 20 / total + 0.00730688 * 25 / total

То же самое я должен сделать для каждого пикселя (думаю, мне нужно добавить kernel_size padding // 2, чтобы иметь возможность использовать весь массив).

Вот мой сценарий

import matplotlib.pylab as plt
import numpy as np
import scipy.stats as st

from scipy import sparse


def generate_data(m, n, density):
    s = 64 * sparse.random(m, n, density=density).A
    return s.astype(np.int8)


def plot_matrix(matrix):
    for (j, i), label in np.ndenumerate(s):
        plt.text(i, j, label, ha='center', va='center')

    plt.imshow(matrix)
    plt.show()


def kernel(n):
    n = n if n % 2 != 0 else n + 1
    mid = n // 2

    m = np.ndarray((n, n, 2))
    for i in range(n):
        for j in range(n):
            m[i, j] = np.array([i, j])

    return np.linalg.norm(m - [mid, mid], axis=2)


s = generate_data(10, 14, 0.25)
plot_matrix(s)

1 Ответ

0 голосов
/ 10 августа 2018

Это было действительно просто, хотя, возможно, не очень эффективно. То, что я должен был сделать, было двумя извилинами:

  • В первом это было сверточное ядро ​​Гаусса с матрицей

    conv_1 = convolve2d (m * mask_clean, k_gauss)

  • Во втором ядро ​​Гаусса с маской

    conv_2 = convolve2d (mask_clean, k_gauss)

В каждой позиции conv_1 будет иметь сумму каждого значения, взвешенного по соответствующему коэффициенту ядра Гаусса. conv_2 будет иметь в каждой позиции сумму всех ненулевых значений. Осталось только разделить их, чтобы получить окончательный результат

# m have the data
mask_clean = (0 < m) & (m_mean - 3*m_std < m) & (m < m_mean + 3*m_std)

# Custom function to create a gaussian kernel
k = gkern(kernlen=5, std=5//2)
k_gauss = st.norm.pdf(k)

conv_1 = convolve2d(m * mask_clean, k_gauss)
conv_2 = convolve2d(mask_clean, k_gauss)
final = conv_1 / conv_2
...