#numpy #where-clause
Вопрос:
Я хотел бы использовать numpy.где проверить значение предыдущей строки, но не знаю, как кодировать
для n1 в диапазоне(len(изображение 1)):
print('input image ',input_folder '\' image1[n1]) print('n') print('image1[n1] ',image1[n1]) print('n') im = Image.open(input_folder '\' image1[n1]) a = np.array(im, dtype='uint8') width, height = im.size print('width ',width) print('height ',height) a = np.where(a==[0,0,0],[255,255,255],a)
!— Измените оператор цикла на np.где —!
for h in range(height): for w in range(width): if h lt;= (height - 2) and w lt;= (width - 2): if a[h,w,0] != 255 and a[h,w,1] != 255 and a[h,w,2] != 255: if (a[h-1,w,0] == 255 and a[h-1,w,1] == 255 and a[h-1,w,2] == 255 and a[h 1,w,0] == 255 and a[h 1,w,1] == 255 and a[h 1,w,2] == 255) or (a[h,w-1,0] == 255 and a[h,w-1,1] == 255 and a[h,w-1,2] == 255 and a[h,w 1,0] == 255 and a[h,w 1,1] == 255 and a[h,w 1,2] == 255):*** Change the above looping statement to np.where(a[-??] = [255,255,255] or a[ ??] = [255,255,255]) so it can run more faster than the for loop statement. --gt; a[h,w,0] = 255 a[h,w,1] = 255 a[h,w,2] = 255
Ответ №1:
Боюсь, вы не сможете использовать np.где здесь.
Причина в том, что:
- условие передается в np.где должен быть указан каждый элемент исходного массива,
- в то время как критерий в вашем коде на самом деле относится только к первым 2 измерениям исходного массива.
Поэтому я придумал другое, довольно элегантное и лаконичное решение.
Часть 1. Как получить первые два индекса элементов, где все элементы в третьем измерении != 255:
Чтобы к нему, по всему массиву, можно было запустить:
np.not_equal(a, 255).all(axis=2)
Часть 2: Как ограничить «диапазон действия» элементами, имеющими как предыдущую, так и следующую строку и столбец.
Вы можете сделать это, передав в приведенный выше код «поддиапазон» исходного массива:
np.not_equal(a[1:-1, 1:-1], 255).all(axis=2))
Вы должны удалить как первый, так и последний столбец и строку (в вашем коде вам не удалось удалить первую строку / столбец).
Но обратите внимание, что на этот раз результирующие индексы на единицу меньше, чем раньше, поэтому на более позднем этапе вам придется добавить к ним 1.
Часть 3: Функция для проверки того, все ли элементы вдоль третьего измерения == 255, для некоторой строки (r) и столбца (c):
def all_eq(arr, r, c): return np.equal(arr[r, c], 255).all()
(будет использоваться в ближайшее время).
Часть 4: Как получить результат:
res = a.copy() for r, c in zip(*np.where(np.not_equal(a[1:-1, 1:-1], 255).all(axis=2))): h = r 1 w = c 1 if all_eq(a, h-1, w) and all_eq(a, h 1, w) or all_eq(a, h, w-1) and all_eq(a, h, w 1): res[h, w] = 255
Обратите внимание, что этот код начинается с создания копии исходного массива (в нем будет содержаться результат).
Затем for r, c in zip(…)
повторяет найденные индексы.
Первые 2 строки цикла добавляют 1 к найденным индексам в поддиапазоне исходного массива, поэтому теперь h и w указывают строку / столбец во всем исходном массиве.
Затем if
проверяет, имеют ли соответствующие соседние пиксели 255 во всех элементах.
Если они это сделают, то поместите 255 во все элементы «текущего» пикселя в результате.
Вы не можете работать с исходным массивом, так как измененные значения в некоторых пикселях «фальсифицируют» оценку условий для последующих пикселей.
Редактировать
После некоторых исследований я обнаружил, что можно использовать np.where, хотя решение немного сложное и включает довольно большое количество методов Numpy:
# Mask 1: Pixels with all elements != 255 m1 = np.zeros((height, width), dtype='int8') idx = np.where(np.not_equal(a, 255).all(axis=2)) m1[idx] = 1 # Pixels with all elements == 255 m2 = np.apply_along_axis(lambda px: np.equal(px, 255).all(), 2, a).astype('int8') # Both adjacent pixels (left / right) == 255 m2a = np.logical_and(np.insert(m2, 0, 0, axis=1)[:,:-1], np.insert(m2, width, 0, axis=1)[:,1:]) # Both adjacent pixels (up / down) == 255 m2b = np.logical_and(np.insert(m2, 0, 0, axis=0)[:-1,:], np.insert(m2, height, 0, axis=0)[1:,:]) # Mask 2: Both adjacent pixels (either vertically or horizontally) == 255 m2 = np.logical_or(m2a, m2b) # The "final" mask msk = np.logical_and(m1, m2) # Generate the result result = np.where(np.expand_dims(msk, 2), 255, a)
Это решение должно быть существенно быстрее, чем моя первая концепция.