Python 将二维阵列切片为较小的二维阵列
有没有办法将numpy中的2d数组切片为更小的2d数组 示例Python 将二维阵列切片为较小的二维阵列,python,numpy,Python,Numpy,有没有办法将numpy中的2d数组切片为更小的2d数组 示例 [[1,2,3,4], -> [[1,2] [3,4] [5,6,7,8]] [5,6] [7,8]] 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 #bloc
[[1,2,3,4], -> [[1,2] [3,4]
[5,6,7,8]] [5,6] [7,8]]
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)
所以我基本上想把一个2x4数组减少为2个2x2数组。正在寻找一种用于图像的通用解决方案。目前,当大的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
angq
确定块大小
代码
[[1,2,3,4], -> [[1,2] [3,4]
[5,6,7,8]] [5,6] [7,8]]
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)
在我看来,这是一个任务或某种变体 e、 g 如果您有一个NxN图像,您可以创建一个2个NxN/2子图像的列表,然后沿另一个轴分割它们
也可以使用。您应该能够使用
重塑
和交换盘的一些组合,将阵列分解为“块”:
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
assert h % nrows == 0, "{} rows is not evenly divisble by {}".format(h, nrows)
assert w % ncols == 0, "{} cols is not evenly divisble by {}".format(w, ncols)
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]]
进入
我已经发布了一个,和一个N维的概括。这种概括使我们对该算法背后的推理有了更多的了解
请注意,还有一个问题。它安排了
不同格式的块(使用更多轴),但它具有(1)的优点
始终返回视图,并且(2)能够处理任何
维度。还有一些其他答案似乎已经非常适合您的具体情况,但您的问题激发了我的兴趣,我想找到一种内存高效的解决方案,可以使用numpy支持的最大维度数,最后我花了一下午的大部分时间想出可能的方法。(该方法本身相对简单,只是我还没有使用numpy支持的大多数真正奇特的功能,所以大部分时间都花在研究numpy有哪些可用功能以及它可以做多少,这样我就不必去做了。)
def blockgen(阵列,bpa):
“”“创建一个生成器,该生成器从给定的
数组(_-like);bpa是由每个轴的块数组成的数组
(最小值为1,必须是数组相应轴大小的除数)
块是使用普通numpy切片选择的,它们将是视图而不是视图
而不是拷贝;这对于正在创建的非常大的多维数组非常有用
阻塞,对于非常大的块,但这也意味着结果必须是
如果要修改,则复制(除非也需要修改原始数据
"
bpa=np.asarray(bpa)#如果bpa还不是ndarray
#参数检查
如果array.ndim!=bpa.size:#bpa与数组维度不匹配
raise VALUERROR(“bpa的大小必须等于数组维度。”)
如果(bpa.dtype!=np.int#bpa必须是所有整数
或(bpa<1)。any()#bpa中的所有值必须大于等于1
或(array.shape%bpa).any()):#%!=0表示不可等分
raise VALUERROR(“bpa({0})必须由非零正整数组成”
“平均分割相应阵列轴的”
“大小”。格式(bpa))
#生成块边缘索引
rgen=(np.r[:array.shape[i]+1:array.shape[i]//blk\u n]
对于i,枚举中的blk_n(bpa))
#为每个轴(轴)构建切片序列
#不能用于使物品易于操作
c=[[np.s_u[i:j]表示i,j在zip中(r[:-1],r[1:])]表示r在rgen中]
#现在让我们来看看积木;这比可能的效率要低一点
#因为numpy不喜欢锯齿状数组,我也不想写
#这是一个很好的例子。
对于np.ndindex(*bpa)中的IDX:
blockbounds=tuple(c[j][idxs[j]]表示范围内的j(bpa.size))
产量数组[块边界]
您可以提问。您可以使用带有np.ndindex()
和重塑()
的一行程序:
要创建所需的结果,请执行以下操作:
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。请注意,我必须交换
ncol
和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))
对工程师的答案进行了一些小的改进,解决了大2d阵列无法完美分割成大小相等的子阵列的情况
def blockfy(a, p, q):
'''
Divides array a into subarrays of size p-by-q
p: block row size
q: block column size
'''
m = a.shape[0] #image row size
n = a.shape[1] #image column size
# pad array with NaNs so it can be divided by p row-wise and by q column-wise
bpr = ((m-1)//p + 1) #blocks per row
bpc = ((n-1)//q + 1) #blocks per column
M = p * bpr
N = q * bpc
A = np.nan* np.ones([M,N])
A[:a.shape[0],:a.shape[1]] = a
block_list = []
previous_row = 0
for row_block in range(bpc):
previous_row = row_block * p
previous_column = 0
for column_block in range(bpr):
previous_column = column_block * q
block = A[previous_row:previous_row+p, previous_column:previous_column+q]
# remove nan columns and nan rows
nan_cols = np.all(np.isnan(block), axis=0)
block = block[:, ~nan_cols]
nan_rows = np.all(np.isnan(block), axis=1)
block = block[~nan_rows, :]
## append
if block.size:
block_list.append(block)
return block_list
示例:
a = np.arange(25)
a = a.reshape((5,5))
out = blockfy(a, 2, 3)
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, 24]])
out[0] ->
array([[0., 1., 2.],
[5., 6., 7.]])
out[1]->
array([[3., 4.],
[8., 9.]])
out[-1]->
array([[23., 24.]])
屈服
[[7 6 2 4 4 2 5 2 3]
[2 3 7 6 8 8 2 6 2]
[4 1 3 1 3 8 1 3 7]
[6 1 1 5 7 2 1 5 8]
[8 8 7 6 6 1 8 8 4]
[6 1 8 2 1 4 5 1 8]
[7 3 4 2 5 6 1 2 7]
[4 6 7 5 8 2 8 2 8]
[6 6 5 5 6 1 2 6 4]]
[[array([[7, 6, 2],
[2, 3, 7],
[4, 1, 3]]), array([[4, 4, 2],
[6, 8, 8],
[1, 3, 8]]), array([[5, 2, 3],
[2, 6, 2],
[1, 3, 7]])], [array([[6, 1, 1],
[8, 8, 7],
[6, 1, 8]]), array([[5, 7, 2],
[6, 6, 1],
[2, 1, 4]]), array([[1, 5, 8],
[8, 8, 4],
[5, 1, 8]])], [array([[7, 3, 4],
[4, 6, 7],
[6, 6, 5]]), array([[2, 5, 6],
[5, 8, 2],
[5, 6, 1]]), array([[1, 2, 7],
[8, 2, 8],
[2, 6, 4]])]]
我发布了我的解决方案。请注意,这段代码实际上并没有创建原始数组的副本,所以它可以很好地处理大数据。此外,如果数组不能被平均分割,它也不会崩溃(但您可以通过删除
ceil
并检查v_切片
和h_切片
是否在不休息的情况下被分割来轻松添加条件)
此代码更改(或者更准确地说,允许您直接访问数组的一部分)如下:
为此:
[[0 1]
[3 4]]
[[2]
[5]]
[[6 7]]
[[8]]
如果您需要实际的副本,这是您正在寻找的
如果你确信大数组可以被平均分割,你可以使用工具。要添加到@Aenaon answer和他的blockfy函数中,如果你正在使用彩色图像/3D数组,这里是我为三通道输入创建224 x 224作物的管道
def blockfy(a, p, q):
'''
Divides array a into subarrays of size p-by-q
p: block row size
q: block column size
'''
m = a.shape[0] #image row size
n = a.shape[1] #image column size
# pad array with NaNs so it can be divided by p row-wise and by q column-wise
bpr = ((m-1)//p + 1) #blocks per row
bpc = ((n-1)//q + 1) #blocks per column
M = p * bpr
N = q * bpc
A = np.nan* np.ones([M,N])
A[:a.shape[0],:a.shape[1]] = a
block_list = []
previous_row = 0
for row_block in range(bpc):
previous_row = row_block * p
previous_column = 0
for column_block in range(bpr):
previous_column = column_block * q
block = A[previous_row:previous_row+p, previous_column:previous_column+q]
# remove nan columns and nan rows
nan_cols = np.all(np.isnan(block), axis=0)
block = block[:, ~nan_cols]
nan_rows = np.all(np.isnan(block), axis=1)
block = block[~nan_rows, :]
## append
if block.size:
block_list.append(block)
return block_list
然后扩展到
for file in os.listdir(path_to_crop): ### list files in your folder
img = io.imread(path_to_crop + file, as_gray=False) ### open image
r = blockfy(img[:,:,0],224,224) ### crop blocks of 224 x 224 for red channel
g = blockfy(img[:,:,1],224,224) ### crop blocks of 224 x 224 for green channel
b = blockfy(img[:,:,2],224,224) ### crop blocks of 224 x 224 for blue channel
for x in range(0,len(r)):
img = np.array((r[x],g[x],b[x])) ### combine each channel into one patch by patch
img = img.astype(np.uint8) ### cast back to proper integers
img_swap = img.swapaxes(0, 2) ### need to swap axes due to the way things were proceesed
img_swap_2 = img_swap.swapaxes(0, 1) ### do it again
Image.fromarray(img_swap_2).save(path_save_crop+str(x)+"bounding" + file,
format = 'jpeg',
subsampling=0,
quality=100) ### save patch with new name etc
你能不能让它更通用一些,使块大小成为变量?(条件是块完全适合原始数组)谢谢你的编辑。你能解释一下算法背后的原因吗?几个月前,我有了一个想法,使用
重塑
和交换
。h//nrows
很有意义,因为这样可以将第一个块的行保持在一起。你需要nrows
一个dncols
成为形状的一部分。-1
告诉整形填充所需的任何数字a
import numpy as np
from math import ceil
a = np.arange(9).reshape(3, 3)
p, q = 2, 2
width, height = a.shape
v_slices = ceil(width / p)
h_slices = ceil(height / q)
for h in range(h_slices):
for v in range(v_slices):
block = a[h * p : h * p + p, v * q : v * q + q]
# do something with a block
[[0 1 2]
[3 4 5]
[6 7 8]]
[[0 1]
[3 4]]
[[2]
[5]]
[[6 7]]
[[8]]
def blockfy(a, p, q):
'''
Divides array a into subarrays of size p-by-q
p: block row size
q: block column size
'''
m = a.shape[0] #image row size
n = a.shape[1] #image column size
# pad array with NaNs so it can be divided by p row-wise and by q column-wise
bpr = ((m-1)//p + 1) #blocks per row
bpc = ((n-1)//q + 1) #blocks per column
M = p * bpr
N = q * bpc
A = np.nan* np.ones([M,N])
A[:a.shape[0],:a.shape[1]] = a
block_list = []
previous_row = 0
for row_block in range(bpc):
previous_row = row_block * p
previous_column = 0
for column_block in range(bpr):
previous_column = column_block * q
block = A[previous_row:previous_row+p, previous_column:previous_column+q]
# remove nan columns and nan rows
nan_cols = np.all(np.isnan(block), axis=0)
block = block[:, ~nan_cols]
nan_rows = np.all(np.isnan(block), axis=1)
block = block[~nan_rows, :]
## append
if block.size:
block_list.append(block)
return block_list
for file in os.listdir(path_to_crop): ### list files in your folder
img = io.imread(path_to_crop + file, as_gray=False) ### open image
r = blockfy(img[:,:,0],224,224) ### crop blocks of 224 x 224 for red channel
g = blockfy(img[:,:,1],224,224) ### crop blocks of 224 x 224 for green channel
b = blockfy(img[:,:,2],224,224) ### crop blocks of 224 x 224 for blue channel
for x in range(0,len(r)):
img = np.array((r[x],g[x],b[x])) ### combine each channel into one patch by patch
img = img.astype(np.uint8) ### cast back to proper integers
img_swap = img.swapaxes(0, 2) ### need to swap axes due to the way things were proceesed
img_swap_2 = img_swap.swapaxes(0, 1) ### do it again
Image.fromarray(img_swap_2).save(path_save_crop+str(x)+"bounding" + file,
format = 'jpeg',
subsampling=0,
quality=100) ### save patch with new name etc