我有以下批处理 RGB 图像数组(4D 数组):
In [55]: img_arr = np.random.randint(0, 255, (10000, 32, 32, 3))
现在,我只想从左上角跨所有 3
channel 裁剪某些尺寸,例如 (12x12
),并且最好沿着批量尺寸(即axis 0
) 也是如此,一气呵成。我的想法是制作一个网格并将其切片。所以,我构建了这个网格:
In [56]: grid = np.c_[np.arange(12)]+ np.r_[np.arange(12)]
In [57]: grid.shape
Out[57]: (12, 12)
但是,当我对数组进行切片时,我得到了一些意想不到的东西:
In [58]: img_arr[:, grid, :].shape
Out[58]: (10000, 12, 12, 32, 3)
我期望并需要结果的形状为 (10000, 12, 12, 3)
,但我不知道 32
来自哪里。
这只是一个例子。理想情况下,我想在图像上的 10 个不同位置进行裁剪。左上、右上、左下、右下等,
但是,通过首先进行左上角裁剪,其余的应该很直观。
此外,正如您所看到的,我需要在单个 4D 数组中沿批处理维度存储超过 100K 图像,因此在进行此类随机裁剪时拥有一个 View 会非常好,因为它将提高内存效率。
最佳答案
我们可以使用slicing为此:我们可以指定第二个和第三个维度的范围,例如:
sub_img = img_arr[:, <b>:12, :12</b> , :]
然后sub_img.shape == (10000, 12, 12, 3)
。因此,这里我们指定一个范围 0
至12
(但我们不需要明确声明 0
)。我们在第二维和第三维上这样做。它也是相当声明性的:我们构造一个 sub_img
其中第一个索引包含所有项 ( :
),第二个索引包含第十二项 ( :12
),依此类推
请注意,我们不需要指定尾部 :
s,我们还可以写:
sub_img = img_arr[:, :12, :12] # no last ":"
切片作为 View
请注意,我们在这里构造一个 View ,我们不复制数组,我们只构造一个 View 。因此,如果我们对 img_arr
进行更改在 View 范围内,我们将能够在 sub_img
中看到它,反之亦然。如果您需要副本,您可以通过 array
传递 View 。构造函数:
sub_img = <b>np.array(</b>img_arr[:, :12, :12]<b>)</b> # making a copy, instead of a view
然而,使用 View 可能是有益的,因为它几乎不使用内存来存储 View (这里大约 144 字节,而副本需要大约 34 兆字节),而且 View 的构建几乎是即时的(通常它会缩放)与维度数),而副本将随元素数量缩放。
使用 slice
的任意维数对象
例如,如果维数是任意的,我们还可以传递 slice
的元组对象。
例如,第一个表达式相当于:
# equivalent to the first code fragment
indices = (slice(None), slice(12), slice(12))
sub_img = img_arr[indices]
因此,如果维数是任意的,我们可以首先构造这样的元组。例如,将除第一个和最后一个之外的所有维度切片为 12 的元组:
# generalized with arbitrary number of dimensions
indices = (slice(None), *(slice(12) for _ in range(img_arr.ndim - 2)))
sub_img = img_arr[indices]
关于python - 从 4D 阵列中裁剪图像的不同部分以进行数据增强,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48409525/