有沒有辦法將二維數組切割成較小的二維數組?將二維數組切片成較小的二維數組
例
[[1,2,3,4], -> [[1,2] [3,4]
[5,6,7,8]] [5,6] [7,8]]
所以我基本上要一個2x4的陣列削減到2個2×2陣列。尋找在圖像上使用的通用解決方案。
有沒有辦法將二維數組切割成較小的二維數組?將二維數組切片成較小的二維數組
例
[[1,2,3,4], -> [[1,2] [3,4]
[5,6,7,8]] [5,6] [7,8]]
所以我基本上要一個2x4的陣列削減到2個2×2陣列。尋找在圖像上使用的通用解決方案。
你應該能夠打破你的數組轉換成 「塊」 使用的reshape
和swapaxes
一些組合:
import numpy as np
def blockshaped(arr, nrows, ncols):
"""
Return an array of shape (n, nrows, ncols) where
n * nrows * ncols = arr.size
If arr is a 2D array, the returned array should look like n subblocks with
each subblock preserving the "physical" layout of arr.
"""
h, w = arr.shape
return (arr.reshape(h//nrows, nrows, -1, ncols)
.swapaxes(1,2)
.reshape(-1, nrows, ncols))
轉c
c = np.arange(24).reshape((4,6))
print(c)
# [[ 0 1 2 3 4 5]
# [ 6 7 8 9 10 11]
# [12 13 14 15 16 17]
# [18 19 20 21 22 23]]
到
print(blockshaped(c, 2, 3))
# [[[ 0 1 2]
# [ 6 7 8]]
# [[ 3 4 5]
# [ 9 10 11]]
# [[12 13 14]
# [18 19 20]]
# [[15 16 17]
# [21 22 23]]]
我已發佈inverse function, unblockshaped
, here,以及N維概括here。泛化提供了對該算法背後原因的更多瞭解。
請注意,也有superbatfish's blockwise_view
。它以不同的格式(使用更多的軸)排列 塊,但它的優點是(1) 總是返回視圖和(2)能夠處理任何維度的數組。
現在,它只是當大2d陣列可以完美切成相同大小的子陣時工作。
代碼波紋管切片
a ->array([[ 0, 1, 2, 3, 4, 5],
[ 6, 7, 8, 9, 10, 11],
[12, 13, 14, 15, 16, 17],
[18, 19, 20, 21, 22, 23]])
到此
block_array->
array([[[ 0, 1, 2],
[ 6, 7, 8]],
[[ 3, 4, 5],
[ 9, 10, 11]],
[[12, 13, 14],
[18, 19, 20]],
[[15, 16, 17],
[21, 22, 23]]])
p
昂q
確定塊大小
代碼
a = arange(24)
a = a.reshape((4,6))
m = a.shape[0] #image row size
n = a.shape[1] #image column size
p = 2 #block row size
q = 3 #block column size
block_array = []
previous_row = 0
for row_block in range(blocks_per_row):
previous_row = row_block * p
previous_column = 0
for column_block in range(blocks_per_column):
previous_column = column_block * q
block = a[previous_row:previous_row+p,previous_column:previous_column+q]
block_array.append(block)
block_array = array(block_array)
在我看來,這是numpy.split
或某個變體的任務。
例如
a = np.arange(30).reshape([5,6]) #a.shape = (5,6)
a1 = np.split(a,3,axis=1)
#'a1' is a list of 3 arrays of shape (5,2)
a2 = np.split(a, [2,4])
#'a2' is a list of three arrays of shape (2,5), (2,5), (1,5)
如果有可以創建,例如,爲2的N×N/2子圖像的列表,然後沿另一個軸將它們劃分NxN的圖像。
還有一些其他答案似乎已經非常適合您的特定情況,但您的問題激起了我對可以使用高達numpy支持的最大維數的內存高效解決方案的興趣,並且我結束了大部分時間都花在了可能的方法上。(該方法本身相對簡單,只是我還沒有使用numpy支持的大多數真正奇特的功能,因此大部分時間都花在研究上以查看numpy可用的數量以及它可以做多少,以使我沒有不必這樣做。)
def blockgen(array, bpa):
"""Creates a generator that yields multidimensional blocks from the given
array(_like); bpa is an array_like consisting of the number of blocks per axis
(minimum of 1, must be a divisor of the corresponding axis size of array). As
the blocks are selected using normal numpy slicing, they will be views rather
than copies; this is good for very large multidimensional arrays that are being
blocked, and for very large blocks, but it also means that the result must be
copied if it is to be modified (unless modifying the original data as well is
intended)."""
bpa = np.asarray(bpa) # in case bpa wasn't already an ndarray
# parameter checking
if array.ndim != bpa.size: # bpa doesn't match array dimensionality
raise ValueError("Size of bpa must be equal to the array dimensionality.")
if (bpa.dtype != np.int # bpa must be all integers
or (bpa < 1).any() # all values in bpa must be >= 1
or (array.shape % bpa).any()): # % != 0 means not evenly divisible
raise ValueError("bpa ({0}) must consist of nonzero positive integers "
"that evenly divide the corresponding array axis "
"size".format(bpa))
# generate block edge indices
rgen = (np.r_[:array.shape[i]+1:array.shape[i]//blk_n]
for i, blk_n in enumerate(bpa))
# build slice sequences for each axis (unfortunately broadcasting
# can't be used to make the items easy to operate over
c = [[np.s_[i:j] for i, j in zip(r[:-1], r[1:])] for r in rgen]
# Now to get the blocks; this is slightly less efficient than it could be
# because numpy doesn't like jagged arrays and I didn't feel like writing
# a ufunc for it.
for idxs in np.ndindex(*bpa):
blockbounds = tuple(c[j][idxs[j]] for j in range(bpa.size))
yield array[blockbounds]
您提問practically the same as this one。您可以使用一個襯墊與np.ndindex()
和reshape()
:
def cutter(a, r, c):
lenr = a.shape[0]/r
lenc = a.shape[1]/c
np.array([a[i*r:(i+1)*r,j*c:(j+1)*c] for (i,j) in np.ndindex(lenr,lenc)]).reshape(lenr,lenc,r,c)
創建結果你想要的:
a = np.arange(1,9).reshape(2,1)
#array([[1, 2, 3, 4],
# [5, 6, 7, 8]])
cutter(a, 1, 2)
#array([[[[1, 2]],
# [[3, 4]]],
# [[[5, 6]],
# [[7, 8]]]])
如果你想有一個解決方案,同時處理情況下,當基質是 不是同樣劃分,你可以用這個:
from operator import add
half_split = np.array_split(input, 2)
res = map(lambda x: np.array_split(x, 2, axis=1), half_split)
res = reduce(add, res)
這裏是一個解決方案基於unutbu的答案處理情況矩陣不能平等 分爲。在這種情況下,它將在使用一些插值之前調整矩陣的大小。你需要OpenCV。請注意,我必須交換ncols
和nrows
才能使其工作,但沒有想到爲什麼。
import numpy as np
import cv2
import math
def blockshaped(arr, r_nbrs, c_nbrs, interp=cv2.INTER_LINEAR):
"""
arr a 2D array, typically an image
r_nbrs numbers of rows
r_cols numbers of cols
"""
arr_h, arr_w = arr.shape
size_w = int(math.floor(arr_w // c_nbrs) * c_nbrs)
size_h = int(math.floor(arr_h // r_nbrs) * r_nbrs)
if size_w != arr_w or size_h != arr_h:
arr = cv2.resize(arr, (size_w, size_h), interpolation=interp)
nrows = int(size_w // r_nbrs)
ncols = int(size_h // c_nbrs)
return (arr.reshape(r_nbrs, ncols, -1, nrows)
.swapaxes(1,2)
.reshape(-1, ncols, nrows))
你能否使它更通用,以便塊大小是變量? (條件是塊完全適合原始數組) – TheMeaningfulEngineer
感謝您的編輯。請您解釋算法背後的推理嗎? – TheMeaningfulEngineer
幾個月前有[另一個問題](http://stackoverflow.com/a/13990648/190597)提到了使用'reshape'和'swapaxes'的想法。 'h // nrows'是有意義的,因爲這會將第一個塊的行保留在一起。這也是有道理的,你需要'nrows'和'ncols'成爲形狀的一部分。 '-1'告訴重塑以填寫任何必要的數字以使重塑有效。以解決方案的形式武裝起來,我只是嘗試了一些東西,直到找到可行的公式。對不起,我對你沒有更深入的解釋。 – unutbu