use*_*142 19 python numpy slice
尝试将尺寸为100x100的灰度图像切割成大小为39x39且重叠的贴片,步幅大小为1.这意味着向下/向下开始一个像素的下一个贴片仅与之前的贴片不同一个额外的列/或行.
代码的粗略轮廓:首先计算每个补丁的索引,以便能够从图像构造补丁的2D阵列,并能够从补丁构建图像:
patches = imgFlat[ind]
Run Code Online (Sandbox Code Playgroud)
'patches'是一个2D数组,每列包含一个矢量形式的补丁.
处理这些补丁,每个补丁单独地和之后再次合并到具有预先计算的索引的图像.
img = np.sum(patchesWithColFlat[ind],axis=2)
Run Code Online (Sandbox Code Playgroud)
由于补丁重叠,最后需要将img与预先计算的权重相乘:
imgOut = weights*imgOut
Run Code Online (Sandbox Code Playgroud)
我的代码非常慢,速度是一个关键问题,因为这应该在ca. 10 ^ 8个补丁.
函数get_indices_for_un_patchify和weights_unpatchify可以预先计算一次,因此速度只是patchify和unpatchify的问题.
谢谢你的任何tipps.
卡洛斯
import numpy as np
import scipy
import collections
import random as rand
def get_indices_for_un_patchify(sImg,sP,step):
''' creates indices for fast patchifying and unpatchifying
INPUTS:
sx image size
sp patch size
step offset between two patches (default == [1,1])
OUTPUTS:
patchInd collection with indices
patchInd.img2patch patchifying indices
patch = img(patchInd.img2patch);
patchInd.patch2img unpatchifying indices
NOTE: * for unpatchifying necessary to add a 0 column to the patch matrix
* matrices are constructed row by row, as normally there are less rows than columns in the
patchMtx
'''
lImg = np.prod(sImg)
indImg = np.reshape(range(lImg), sImg)
# no. of patches which fit into the image
sB = (sImg - sP + step) / step
lb = np.prod(sB)
lp = np.prod(sP)
indImg2Patch = np.zeros([lp, lb])
indPatch = np.reshape(range(lp*lb), [lp, lb])
indPatch2Img = np.ones([sImg[0],sImg[1],lp])*(lp*lb+1)
# default value should be last column
iRow = 0;
for jCol in range(sP[1]):
for jRow in range(sP[0]):
tmp1 = np.array(range(0, sImg[0]-sP[0]+1, step[0]))
tmp2 = np.array(range(0, sImg[1]-sP[1]+1, step[1]))
sel1 = jRow + tmp1
sel2 = jCol + tmp2
tmpIndImg2Patch = indImg[sel1,:]
# do not know how to combine following 2 lines in python
tmpIndImg2Patch = tmpIndImg2Patch[:,sel2]
indImg2Patch[iRow, :] = tmpIndImg2Patch.flatten()
# next line not nice, but do not know how to implement it better
indPatch2Img[min(sel1):max(sel1)+1, min(sel2):max(sel2)+1, iRow] = np.reshape(indPatch[iRow, :, np.newaxis], sB)
iRow += 1
pInd = collections.namedtuple
pInd.patch2img = indPatch2Img
pInd.img2patch = indImg2Patch
return pInd
def weights_unpatchify(sImg,pInd):
weights = 1./unpatchify(patchify(np.ones(sImg), pInd), pInd)
return weights
# @profile
def patchify(img,pInd):
imgFlat = img.flat
# imgFlat = img.flatten()
ind = pInd.img2patch.tolist()
patches = imgFlat[ind]
return patches
# @profile
def unpatchify(patches,pInd):
# add a row of zeros to the patches matrix
h,w = patches.shape
patchesWithCol = np.zeros([h+1,w])
patchesWithCol[:-1,:] = patches
patchesWithColFlat = patchesWithCol.flat
# patchesWithColFlat = patchesWithCol.flatten()
ind = pInd.patch2img.tolist()
img = np.sum(patchesWithColFlat[ind],axis=2)
return img
Run Code Online (Sandbox Code Playgroud)
我将这些功能称为例如随机图像
if __name__ =='__main__':
img = np.random.randint(255,size=[100,100])
sImg = img.shape
sP = np.array([39,39]) # size of patch
step = np.array([1,1]) # sliding window step size
pInd = get_indices_for_un_patchify(sImg,sP,step)
patches = patchify(img,pInd)
imgOut = unpatchify(patches,pInd)
weights = weights_unpatchify(sImg,pInd)
imgOut = weights*imgOut
print 'Difference of img and imgOut = %.7f' %sum(img.flatten() - imgOut.flatten())
Run Code Online (Sandbox Code Playgroud)
jor*_*eca 20
"补充"数组的一种有效方法,即获取原始数组的窗口数组,就是创建一个带有自定义步长的视图,即跳转到以下元素的字节数.将numpy数组视为(荣耀的)内存块可能会有所帮助,然后strides是一种将索引映射到内存地址的方法.
例如,在
a = np.arange(10).reshape(2, 5)
Run Code Online (Sandbox Code Playgroud)
a.itemsize
等于4(即,每个元素为4个字节或32位)并且a.strides
是(20, 4)
(5个元素,1个元素),因此它a[1,2]
指的是在第一个元素之后是1*20 + 2*4
字节(或1*5 + 2
元素)的元素:
0 1 2 3 4
5 6 7 x x
Run Code Online (Sandbox Code Playgroud)
实际上,这些元素一个接一个地放在内存中,0 1 2 3 4 5 6 7 x x
但是我们可以将它作为一个2D数组索引.
基于这个概念,我们可以重写patchify
如下
def patchify(img, patch_shape):
img = np.ascontiguousarray(img) # won't make a copy if not needed
X, Y = img.shape
x, y = patch_shape
shape = ((X-x+1), (Y-y+1), x, y) # number of patches, patch_shape
# The right strides can be thought by:
# 1) Thinking of `img` as a chunk of memory in C order
# 2) Asking how many items through that chunk of memory are needed when indices
# i,j,k,l are incremented by one
strides = img.itemsize*np.array([Y, 1, Y, 1])
return np.lib.stride_tricks.as_strided(img, shape=shape, strides=strides)
Run Code Online (Sandbox Code Playgroud)
此函数返回一个视图img
,因此没有分配内存,它只运行几十微秒.输出形状并不完全符合您的要求,实际上必须将其复制才能获得该形状.
在处理比基本数组大得多的数组视图时,必须要小心,因为操作可以触发需要分配大量内存的副本.在你的情况下,由于数组不是太大而且没有那么多补丁,它应该没问题.
最后,我们可以稍微调整补丁数组:
patches = patchify(img, (39,39))
contiguous_patches = np.ascontiguousarray(patches)
contiguous_patches.shape = (-1, 39**2)
Run Code Online (Sandbox Code Playgroud)
这不会重现补丁函数的输出,因为您可以按照Fortran顺序开发补丁.我建议你改用它,因为
它会导致更自然的索引(即,第一个补丁是补丁[0]而不是补丁[:,0]用于您的解决方案).
numpy在任何地方使用C排序也更容易,因为你需要更少的输入(你可以避免使用order ='F'之类的东西,默认情况下以C顺序创建数组......).
如果你坚持"提示":strides = img.itemsize * np.array([1, Y, Y, 1])
使用.reshape(..., order='F')
在contiguous_patches
最后它转.T