Python Numpy视图在不复制的情况下重塑形状(二维移动/滑动窗口、跨步、屏蔽内存结构)

Python Numpy视图在不复制的情况下重塑形状(二维移动/滑动窗口、跨步、屏蔽内存结构),python,image,numpy,scikit-learn,scikit-image,Python,Image,Numpy,Scikit Learn,Scikit Image,我将图像存储为2d numpy数组(可能是多维数组) 我可以在该数组上创建一个反映2d滑动窗口的视图,但是当我重新调整它的形状,使每一行都是一个平坦的窗口(行是窗口,列是该窗口中的一个像素)时,python会生成一个完整副本。这是因为我使用的是典型的步幅技巧,而新形状在内存中不是连续的 我需要这个,因为我要将整个大图像传递给sklearn分类器,该分类器接受2d矩阵,其中没有批处理/部分拟合过程,并且完整的扩展副本对于内存来说太大 我的问题是:有没有一种方法可以在不完全复制视图的情况下实现这一点

我将图像存储为2d numpy数组(可能是多维数组)

我可以在该数组上创建一个反映2d滑动窗口的视图,但是当我重新调整它的形状,使每一行都是一个平坦的窗口(行是窗口,列是该窗口中的一个像素)时,python会生成一个完整副本。这是因为我使用的是典型的步幅技巧,而新形状在内存中不是连续的

我需要这个,因为我要将整个大图像传递给sklearn分类器,该分类器接受2d矩阵,其中没有批处理/部分拟合过程,并且完整的扩展副本对于内存来说太大

我的问题是:有没有一种方法可以在不完全复制视图的情况下实现这一点

我相信答案要么是(1)我忽略的关于Strips或numpy内存管理的内容,要么是(2)python的某种屏蔽内存结构,它可以模拟numpy数组,甚至可以模拟包含cython的外部包,如sklearn

在内存中的2d图像的移动窗口上进行训练的任务很常见,但我所知道的直接解释补丁的唯一尝试是Vigra项目()

谢谢你的帮助

>>> A=np.arange(9).reshape(3,3)
>>> print A
[[0 1 2]
 [3 4 5]
 [6 7 8]]
>>> xstep=1;ystep=1; xsize=2; ysize=2
>>> window_view = np.lib.stride_tricks.as_strided(A, ((A.shape[0] - xsize + 1) / xstep, (A.shape[1] - ysize + 1) / ystep, xsize, ysize),
...       (A.strides[0] * xstep, A.strides[1] * ystep, A.strides[0], A.strides[1]))
>>> print window_view 
[[[[0 1]
   [3 4]]

  [[1 2]
   [4 5]]]


 [[[3 4]
   [6 7]]

  [[4 5]
   [7 8]]]]
>>> 
>>> np.may_share_memory(A,window_view)
True
>>> B=window_view.reshape(-1,xsize*ysize)
>>> np.may_share_memory(A,B)
False

您的任务不可能只使用步幅,但NumPy确实支持 一种执行此任务的数组。带跨步和
掩蔽阵列
您可以为数据创建所需的视图。然而,并非所有 NumPy函数支持使用
掩码_数组进行操作,因此
可能scikit learn也不能很好地处理这些问题

让我们先来看看我们在这里尝试做什么。 考虑示例的输入数据。基本上,数据是 内存中只有一个一维数组,如果我们考虑 这是一种进步。阵列看起来只是二维的,因为我们 确定了它的形状。使用步幅,可以定义形状 像这样:

from numpy.lib.stride_tricks import as_strided

base = np.arange(9)
isize = base.itemsize
A = as_strided(base, shape=(3, 3), strides=(3 * isize, isize))
现在的目标是将这种步幅设置为
base
,以便它命令 像末端数组中的数字,
B
。换句话说,我们要求 整数
a
b
使得

>>> as_strided(base, shape=(4, 4), strides=(a, b))
array([[0, 1, 3, 4],
       [1, 2, 4, 5],
       [3, 4, 6, 7],
       [4, 5, 7, 8]])
但这显然是不可能的。我们能达到的最接近的视角是 这是一个滚动窗口,位于基础上:

>>> C = as_strided(base, shape=(5, 5), strides=(isize, isize))
>>> C
array([[0, 1, 2, 3, 4],
       [1, 2, 3, 4, 5],
       [2, 3, 4, 5, 6],
       [3, 4, 5, 6, 7],
       [4, 5, 6, 7, 8]])
但是这里的区别是我们有额外的列和行,这 我们想摆脱。因此,实际上我们要求的是 滚动窗口,该窗口不是连续的,并且在规则位置进行跳跃 间隔。在这个例子中,我们希望每三个项目 从窗口中排除,并在两行后跳过一项

我们可以将其描述为一个
掩蔽数组

>>> mask = np.zeros((5, 5), dtype=bool)
>>> mask[2, :] = True
>>> mask[:, 2] = True
>>> D = np.ma.masked_array(C, mask=mask)
这个数组正好包含我们想要的数据,它只是一个 查看原始数据。我们可以确认数据是相等的

>>> D.data[~D.mask].reshape(4, 4)
array([[0, 1, 3, 4],
       [1, 2, 4, 5],
       [3, 4, 6, 7],
       [4, 5, 7, 8]])
但正如我在开始时所说,scikit很可能会学习 不理解掩码数组。如果它只是将其转换为 数组,则数据将出错:

>>> np.array(D)
array([[0, 1, 2, 3, 4],
       [1, 2, 3, 4, 5],
       [2, 3, 4, 5, 6],
       [3, 4, 5, 6, 7],
       [4, 5, 6, 7, 8]])

我认为这是不可能的,即使你将
数组传递给sklearn分类器,我认为如果数据不是连续的,大多数(如果不是全部的话)分类器都会复制你的数据。是的,我很确定这是不可能的。很抱歉如果你有办法,请告诉我;)另外:直接输入图像可能不是一个好主意,计算功能可能会解决您的问题。根据numpy规则,明确排除第(1)项,
sklearn.feature\u extraction.image.extract\u patches
为您提供的正是您所谈论的视图,重塑它肯定会复制。您确定一次需要多个图像的所有补丁吗?无论您的目标是什么,您都可能希望研究在线/批处理算法。例如,试试
sgdclassizer
。@HYRY实际上取决于估计器。连续数据通常不是必需的。您的答案是与的相关链接。OP希望在不复制的情况下重塑块视图。你的屏蔽很诱人-除了许多
ma
函数通过使用
filled
将屏蔽值替换为无害值(例如
filled(0)
表示
ma.sum
)。这是每个屏蔽操作的临时副本。