О заявлении numpy.where

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

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