У меня есть большое изображение, на котором я хочу выполнить операцию из движущегося окна по всему окну. Вот воспроизводимый пример:
Учитывая массив с именем image формы (5, 5), мне нужно извлечь подмножества из массива в окнах 3x3.
import numpy as np
# example dada
image = np.array([[1,2,3,4,5], [1,2,3,4,5], [1,2,3,4,5], [1,2,3,4,5], [1,2,3,4,5]])
Выход[1]:
array([[1, 2, 3, 4, 5],
[1, 2, 3, 4, 5],
[1, 2, 3, 4, 5],
[1, 2, 3, 4, 5],
[1, 2, 3, 4, 5]])
Для окна 3x3 первое подмножество:
# first iteration
window_size = 3
image[0:window_size, 0:window_size] # from 1st to 3th row and from 1st to 3th col
Выход[2]:
array([[1, 2, 3],
[1, 2, 3],
[1, 2, 3]])
Таким образом, я могу получить доступ к различным подмножествам, используя вложенный цикл:
for i in range(0, image.shape[0]-window_size+1):
for j in range(0, image.shape[1]-window_size+1):
a = (j,i) # top left value
b = (j,i+window_size) # top right value
c = (j+window_size,i) # bottom left value
d = (j+window_size,i+window_size) # bottom right value
print('Window position', a,b,c,d)
subset = image[i:i+window_size, j:j+window_size]
print(subset)
Есть ли более эффективный способ выполнить эту операцию и избежать выполнения этих двух циклов?
Вы можете использовать np.lib.stride_tricks.sliding_window_view(image, (3, 3)), но это зависит от того, что вы хотите с этим делать…
Кстати, ваш код для нарезки неверен, это должно быть: image[i:i+window_size, j:j+window_size]
Ваш подход - это то, чего я жду. Большое спасибо. PS: Исправил ошибку в воспроизводимом коде.
Есть несколько других вопросов о векторизации движущихся окон в массивах, на которые вы должны ссылаться, здесь , здесь и здесь
Я не знал, что вы можете использовать кортежи для индексации таким образом, поэтому я попытался запустить ваш код. Как я и ожидал, image[a:b,a:c] не работает. Наверное, так и должно быть image[a[0]:d[0],a[1]:d[1]].






Попробуйте выполнить следующие действия:
import numpy as np
# example data
image = np.array([[1, 2, 3, 4, 5],
[1, 2, 3, 4, 5],
[1, 2, 3, 4, 5],
[1, 2, 3, 4, 5],
[1, 2, 3, 4, 5]])
# Define the window size
window_size = 3
# Calculate the number of rows and columns in the output array
output_shape = (image.shape[0] - window_size + 1, image.shape[1] -
window_size + 1)
# Create an empty array to store the subsets
subsets = np.empty(output_shape, dtype=object)
# Extract subsets using nested loops
for i in range(output_shape[0]):
for j in range(output_shape[1]):
subsets[i, j] = image[i:i + window_size, j:j + window_size]
# Print the extracted subsets
for i in range(output_shape[0]):
for j in range(output_shape[1]):
print(f"Subset at position ({i}, {j}):\n{subsets[i, j]}\n")
Этот ответ был бы более полезным, если бы он объяснял, как он отвечает на вопрос - ответы только на код никогда не бывают такими полезными, как ответы, объясняющие решение. Тем не менее, вопрос заключался в следующем: «Есть ли более эффективный способ выполнить эту операцию и избежать выполнения этих двух циклов?», поэтому код, использующий циклы, вероятно, не отвечает на вопрос.
Можете ли вы объяснить, почему ваш ответ так похож на ответ, сгенерированный ChatGPT?
как это лучше?
Благодаря комментариям @CrisLuengo и @mozway я могу ответить на свой вопрос. Действительно, выделенная функция np.lib.stride_tricks.sliding_window_view более эффективна, чем вложенный цикл. Вот небольшой тест тайминга с размером окна 3х3 для арий 100х100, 1000х1000 и 10000х10000.
import numpy as np
import time
image = np.random.random((10000, 10000))
window_size = 3
# nested loop
start = time.time()
subsets = []
for i in range(0, image.shape[0]-window_size+1):
for j in range(0, image.shape[1]-window_size+1):
subset = image[i:i+window_size, j:j+window_size]
subsets.append(subset)
end = time.time()
print(end - start)
# dedicated function
start = time.time()
subset = np.lib.stride_tricks.sliding_window_view(image, (window_size, window_size))
subsets = subset.reshape(subset.shape[0]*subset.shape[1], window_size, window_size)
end = time.time()
print(end - start)
Однако может быть еще более эффективное решение с использованием scipy.ndimage.generic_filter. Эта функция позволяет применять определяемую пользователем функцию к различным позициям окна. Если я найду лучшее решение с этим подходом, я обновлю свой ответ.
Подумайте об использовании time.perf_counter(), если вы пытаетесь измерить эффективность подходов.