Вдохновленный this post
, мы расширим его до 3D
регистра массива, помня, что строка будет означать, что первая ось для 3D
массивов изображений и столбцов будет второй,Таким образом, удаление одного элемента в строке даст нам на один элемент меньше вдоль второй оси.
Решение будет выглядеть примерно так -
def delete_per_row_3D(a, remove_idx):
mask = np.ones(a.shape[:-1],dtype=bool)
mask[np.arange(len(remove_idx)), remove_idx] = False
return a[mask].reshape(np.array(a.shape)-[0,1,0])
Пример выполнения -
In [43]: np.random.seed(0)
...: a = np.random.randint(10,100,(2,4,3))
In [44]: a
Out[44]:
array([[[54, 57, 74],
[77, 77, 19],
[93, 31, 46],
[97, 80, 98]],
[[98, 22, 68],
[75, 49, 97],
[56, 98, 91],
[47, 35, 87]]])
In [45]: remove_idx = np.array([2,0]) # length be a.shape[0],
# as no. of rows in 3D image array would be that
In [46]: delete_per_row_3D(a, remove_idx)
Out[46]:
array([[[54, 57, 74],
[77, 77, 19],
[97, 80, 98]],
[[75, 49, 97],
[56, 98, 91],
[47, 35, 87]]])
Визуализация с каналами
Чтобы помочь читателям лучше визуализировать его, рассмотрим три фрагмента для каналов RGB / BGR -
In [47]: a[...,0]
Out[47]:
array([[54, 77, 93, 97],
[98, 75, 56, 47]])
In [48]: a[...,1]
Out[48]:
array([[57, 77, 31, 80],
[22, 49, 98, 35]])
In [49]: a[...,2]
Out[49]:
array([[74, 19, 46, 98],
[68, 97, 91, 87]])
Мы хотим удалитьcolumn-2
из первого ряда и column-0
из второго ряда. Итак, рассмотрим те, которые удаляются из всех трех каналов, то есть 93,31,46
и 98,22,68
удалены. Таким образом, мы закончим с показанным выводом ранее с одним элементом меньше вдоль второй оси.
Альтернативы
Снова из ранее связанного поста, еще две альтернативыbe -
def delete_per_row_3D_v2(a, remove_idx):
mask = remove_idx[:,None]!=np.arange(a.shape[1])
return a[mask].reshape(np.array(a.shape)-[0,1,0])
def delete_per_row_3D_v3(a, remove_idx):
m,n = a.shape[:-1]
rm = remove_idx+n*np.arange(m)
return np.delete(a.reshape(-1,a.shape[-1]),rm,axis=0).reshape(m,n-1,-1)
Переместите его на следующий уровень с использованием подхода на основе вида
Мы будем использовать метод на основе вида для маскировки пикселей в группе на основе и, следовательно, достижения основных преимуществ в отношении памяти и, следовательно, производительности, как показано ниже -
def delete_per_row_3D_view(a, remove_idx):
m,n,r = a.shape
mask = np.ones((m,n),dtype=bool)
mask[np.arange(len(remove_idx)), remove_idx] = False
vd = np.dtype((np.void, a.dtype.itemsize * r))
a_masked = a.view(vd).ravel()[mask.flat].view(a.dtype)
return a_masked.reshape(m,-1,r)
Сравнительный анализ
Мы включаем все векторизованные методы здесь (включая все из этого поста)и из поста @Paul Panzer).
1) Корпус 3D-матрицы OP 640x340:
In [180]: np.random.seed(0)
...: a = np.random.randint(0,256,(640,340,3)).astype(np.uint8)
...: remove_idx = np.random.randint(0,340,(640))
In [181]: %timeit delete_per_row_3D(a, remove_idx)
...: %timeit delete_per_row_3D_v2(a, remove_idx)
...: %timeit delete_per_row_3D_v3(a, remove_idx)
...: %timeit delete_per_row_3D_view(a, remove_idx)
...: %timeit pp(a, remove_idx)
...: %timeit pp_flat(a, remove_idx)
100 loops, best of 3: 5.09 ms per loop
100 loops, best of 3: 5.31 ms per loop
100 loops, best of 3: 3.58 ms per loop
1000 loops, best of 3: 211 µs per loop
100 loops, best of 3: 4.19 ms per loop
1000 loops, best of 3: 1.23 ms per loop
2) Корпус 3D-массива Small 64x34:
In [182]: np.random.seed(0)
...: a = np.random.randint(0,256,(64,34,3)).astype(np.uint8)
...: remove_idx = np.random.randint(0,34,(64))
In [183]: %timeit delete_per_row_3D(a, remove_idx)
...: %timeit delete_per_row_3D_v2(a, remove_idx)
...: %timeit delete_per_row_3D_v3(a, remove_idx)
...: %timeit delete_per_row_3D_view(a, remove_idx)
...: %timeit pp(a, remove_idx)
...: %timeit pp_flat(a, remove_idx)
10000 loops, best of 3: 61.9 µs per loop
10000 loops, best of 3: 61.7 µs per loop
10000 loops, best of 3: 61.3 µs per loop
100000 loops, best of 3: 12.9 µs per loop
10000 loops, best of 3: 49.8 µs per loop
10000 loops, best of 3: 22.2 µs per loop
3)Большой корпус массива 6400x3400 3D:
In [184]: np.random.seed(0)
...: a = np.random.randint(0,256,(6400,3400,3)).astype(np.uint8)
...: remove_idx = np.random.randint(0,3400,(6400))
In [185]: %timeit delete_per_row_3D(a, remove_idx)
...: %timeit delete_per_row_3D_v2(a, remove_idx)
...: %timeit delete_per_row_3D_v3(a, remove_idx)
...: %timeit delete_per_row_3D_view(a, remove_idx)
...: %timeit pp(a, remove_idx)
...: %timeit pp_flat(a, remove_idx)
1 loop, best of 3: 649 ms per loop
1 loop, best of 3: 669 ms per loop
1 loop, best of 3: 434 ms per loop
10 loops, best of 3: 47.5 ms per loop
1 loop, best of 3: 415 ms per loop
10 loops, best of 3: 127 ms per loop
Итак, метод view-based
: delete_per_row_3D_view
уничтожает все другие подходы всех размеров.