Пиксельные соседи в массиве 2d (изображение) с использованием Python
У меня такой массив numpy:
x = np.array([[1,2,3],[4,5,6],[7,8,9]])
Мне нужно создать функцию, чтобы называть ее "соседи" со следующим входным параметром:
- x: массив numpy 2d
- (i, j): индекс элемента в массиве 2d
- d: радиус окрестности
В качестве вывода я хочу получить соседей ячейки i,j
с заданным расстоянием d
.
Поэтому, если я запустил
neighbors(im, i, j, d=1) with i = 1 and j = 1 (element value = 5)
Мне нужно получить индексы следующих значений: [1,2,3,4,6,7,8,9]
. Надеюсь, я разъясню.
Есть ли библиотека, подобная scipy, которая имеет дело с этим?
Я сделал что-то, но это грубое решение.
def pixel_neighbours(self, p):
rows, cols = self.im.shape
i, j = p[0], p[1]
rmin = i - 1 if i - 1 >= 0 else 0
rmax = i + 1 if i + 1 < rows else i
cmin = j - 1 if j - 1 >= 0 else 0
cmax = j + 1 if j + 1 < cols else j
neighbours = []
for x in xrange(rmin, rmax + 1):
for y in xrange(cmin, cmax + 1):
neighbours.append([x, y])
neighbours.remove([p[0], p[1]])
return neighbours
Как я могу улучшить это?
Ответы
Ответ 1
РЕДАКТИРОВАТЬ: ah crap, мой ответ - это просто написать im[i-d:i+d+1, j-d:j+d+1].flatten()
, но написанный непонятным образом:)
Хороший старый трюк с поворотным окном может помочь здесь:
import numpy as np
from numpy.lib.stride_tricks import as_strided
def sliding_window(arr, window_size):
""" Construct a sliding window view of the array"""
arr = np.asarray(arr)
window_size = int(window_size)
if arr.ndim != 2:
raise ValueError("need 2-D input")
if not (window_size > 0):
raise ValueError("need a positive window size")
shape = (arr.shape[0] - window_size + 1,
arr.shape[1] - window_size + 1,
window_size, window_size)
if shape[0] <= 0:
shape = (1, shape[1], arr.shape[0], shape[3])
if shape[1] <= 0:
shape = (shape[0], 1, shape[2], arr.shape[1])
strides = (arr.shape[1]*arr.itemsize, arr.itemsize,
arr.shape[1]*arr.itemsize, arr.itemsize)
return as_strided(arr, shape=shape, strides=strides)
def cell_neighbors(arr, i, j, d):
"""Return d-th neighbors of cell (i, j)"""
w = sliding_window(arr, 2*d+1)
ix = np.clip(i - d, 0, w.shape[0]-1)
jx = np.clip(j - d, 0, w.shape[1]-1)
i0 = max(0, i - d - ix)
j0 = max(0, j - d - jx)
i1 = w.shape[2] - max(0, d - i + ix)
j1 = w.shape[3] - max(0, d - j + jx)
return w[ix, jx][i0:i1,j0:j1].ravel()
x = np.arange(8*8).reshape(8, 8)
print x
for d in [1, 2]:
for p in [(0,0), (0,1), (6,6), (8,8)]:
print "-- d=%d, %r" % (d, p)
print cell_neighbors(x, p[0], p[1], d=d)
Не делал никаких таймингов здесь, но возможно, что эта версия имеет разумную производительность.
Для получения дополнительной информации выполните поиск в сети с фразами "num of number of rollning" или "скользящим окном numpy".
Ответ 2
Посмотрите scipy.ndimage.generic_filter
.
В качестве примера:
import numpy as np
import scipy.ndimage as ndimage
def test_func(values):
print values
return values.sum()
x = np.array([[1,2,3],[4,5,6],[7,8,9]])
footprint = np.array([[1,1,1],
[1,0,1],
[1,1,1]])
results = ndimage.generic_filter(x, test_func, footprint=footprint)
По умолчанию он будет "отражать" значения на границах. Вы можете управлять этим с помощью аргумента ключевого слова mode
.
Однако, если вы хотите сделать что-то подобное, есть хороший шанс, что вы можете выразить свою проблему как нечто вроде свертки. Если это так, будет намного быстрее разбить его на сверточные шаги и использовать более оптимизированные функции (например, большую часть scipy.ndimage
).
Ответ 3
Я не знаю о каких-либо библиотечных функциях для этого, но вы можете легко написать что-то вроде этого самостоятельно, используя отличную функциональность нарезки numpy:
import numpy as np
def neighbors(im, i, j, d=1):
n = im[i-d:i+d+1, j-d:j+d+1].flatten()
# remove the element (i,j)
n = np.hstack((b[:len(b)//2],b[len(b)//2+1:] ))
return n
Конечно, вы должны выполнить некоторые проверки диапазона, чтобы избежать доступа за пределы границ.
Ответ 4
Я согласен с ответом Джо Кингтона, просто добавляет к следам
import numpy as np
from scipy.ndimage import generate_binary_structure
from scipy.ndimage import iterate_structure
foot = np.array(generate_binary_structure(2, 1),dtype=int)
или для больших/разных отпечатков для ex.
np.array(iterate_structure(foot , 2),dtype=int)
Ответ 5
Возможно, используйте KDTree в SciPy?