Python Numpy视图在不复制的情况下重塑形状(二维移动/滑动窗口、跨步、屏蔽内存结构)
我将图像存储为2d numpy数组(可能是多维数组) 我可以在该数组上创建一个反映2d滑动窗口的视图,但是当我重新调整它的形状,使每一行都是一个平坦的窗口(行是窗口,列是该窗口中的一个像素)时,python会生成一个完整副本。这是因为我使用的是典型的步幅技巧,而新形状在内存中不是连续的 我需要这个,因为我要将整个大图像传递给sklearn分类器,该分类器接受2d矩阵,其中没有批处理/部分拟合过程,并且完整的扩展副本对于内存来说太大 我的问题是:有没有一种方法可以在不完全复制视图的情况下实现这一点 我相信答案要么是(1)我忽略的关于Strips或numpy内存管理的内容,要么是(2)python的某种屏蔽内存结构,它可以模拟numpy数组,甚至可以模拟包含cython的外部包,如sklearn 在内存中的2d图像的移动窗口上进行训练的任务很常见,但我所知道的直接解释补丁的唯一尝试是Vigra项目() 谢谢你的帮助Python Numpy视图在不复制的情况下重塑形状(二维移动/滑动窗口、跨步、屏蔽内存结构),python,image,numpy,scikit-learn,scikit-image,Python,Image,Numpy,Scikit Learn,Scikit Image,我将图像存储为2d numpy数组(可能是多维数组) 我可以在该数组上创建一个反映2d滑动窗口的视图,但是当我重新调整它的形状,使每一行都是一个平坦的窗口(行是窗口,列是该窗口中的一个像素)时,python会生成一个完整副本。这是因为我使用的是典型的步幅技巧,而新形状在内存中不是连续的 我需要这个,因为我要将整个大图像传递给sklearn分类器,该分类器接受2d矩阵,其中没有批处理/部分拟合过程,并且完整的扩展副本对于内存来说太大 我的问题是:有没有一种方法可以在不完全复制视图的情况下实现这一点
>>> 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
)。这是每个屏蔽操作的临时副本。