Python 将图像切片为重叠面片并将面片合并到图像的快速方法
尝试将大小为100x100的灰度图像切片为大小为39x39的重叠块,步幅大小为1。这意味着从右/或下一个像素开始的下一个面片与上一个面片仅在一个附加列/行中不同 代码的大致轮廓:首先计算每个补丁的索引,以便能够 从图像构建二维面片阵列,并能够从面片构建图像:Python 将图像切片为重叠面片并将面片合并到图像的快速方法,python,numpy,slice,Python,Numpy,Slice,尝试将大小为100x100的灰度图像切片为大小为39x39的重叠块,步幅大小为1。这意味着从右/或下一个像素开始的下一个面片与上一个面片仅在一个附加列/行中不同 代码的大致轮廓:首先计算每个补丁的索引,以便能够 从图像构建二维面片阵列,并能够从面片构建图像: patches = imgFlat[ind] “面片”是一个二维数组,每列包含向量形式的面片 对这些面片进行处理,每个面片单独合并,然后使用预先计算的索引再次合并到一幅图像中 img = np.sum(patchesWithColFlat
patches = imgFlat[ind]
“面片”是一个二维数组,每列包含向量形式的面片
对这些面片进行处理,每个面片单独合并,然后使用预先计算的索引再次合并到一幅图像中
img = np.sum(patchesWithColFlat[ind],axis=2)
当面片重叠时,有必要在最后将img与预先计算的权重相乘:
imgOut = weights*imgOut
我的代码非常慢,速度是一个关键问题,因为这应该在大约10^8个补丁上完成
函数获取用于修补和权重修补的索引,可以预先计算一次,因此速度只是修补和修补的问题。
谢谢你的小费
卡洛斯
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
我在这里调用这些函数,例如,使用随机图像
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())
“修补”数组的一种有效方法是创建一个视图,其中包含要跳转到以下元素的自定义字节数。将numpy数组视为(美化的)内存块可能会有所帮助,而跨步是将索引映射到内存地址的一种方式
例如,在
a = np.arange(10).reshape(2, 5)
a.itemsize
等于4(即每个元素4个字节或32位),而a.strips
是(20,4)
(5个元素,1个元素),因此a[1,2]
指第一个元素之后1*20+2*4
字节(或1*5+2
元素)的元素:
0 1 2 3 4
5 6 7 x x
事实上,元素一个接一个地放在内存中,01 2 3 4 5 6 7 x
,但是跨步让我们将其作为2D数组进行索引
基于这个概念,我们可以重写补丁
,如下所示
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)
此函数返回img
视图,因此不分配内存,只需几十微秒即可运行。输出形状并不完全是您想要的,事实上,必须复制它才能获得该形状
在处理比基数组大得多的数组视图时必须小心,因为操作可能会触发需要分配大量内存的副本。在您的情况下,因为阵列不是太大,也没有那么多补丁,所以应该可以
最后,我们可以稍微展开补丁阵列:
patches = patchify(img, (39,39))
contiguous_patches = np.ascontiguousarray(patches)
contiguous_patches.shape = (-1, 39**2)
这不会重现patchify函数的输出,因为您是按照Fortran的顺序开发补丁的。我建议你改用这个,因为
“提示”在您坚持的情况下:
strips=img.itemsize*np.array([1,Y,Y,1])
,使用。在连续的补丁上重塑(…,order='F')
,最后将其转置。T
您需要如何处理补丁?也许整件事可以做为一个卷积。你的patchify
功能实际上可以免费使用步幅玩把戏,但我不确定它的反作用。这些补丁用于训练神经网络。100x100图像被切成39x39的补丁。这些补丁被输入神经网络。然后将神经网络的输出(也包括面片)合并在一起,再次得到100x100(或更小)的图像。必须使用不同的100x100图像多次执行此操作。所以我真的很感兴趣,你认为如何加速补丁功能,如何“免费”完成它?你为什么不使用scikit的“从2D函数提取补丁”?它只提供重叠的面片。对于重建,有“从二维面片重建”功能。非常感谢。从这个答案中学到了很多关于python的知识@乔雷加:真的很快。我将做作业:)并用Fortran命令发布解决方案。对于那些不理解贴出的答案的人,(我没有),看一下帮助(np.lib.stride\u tricks.as\u strided)并了解更多关于stride\u技巧的信息。但是有人知道如何使unpatchify函数更快吗?@user2425142我扩展了我的答案,我希望现在答案更清楚。不过,对于反问题,我没有类似的解决方案。我不确定是把这两个问题放在一起好还是分开好。谢谢你的扩展。我在stackoverflow上发布了另一个问题,只涉及合并部分。希望有人知道一种快速的方法。然后我将编辑这个问题,包括快速合并部分,并关闭这两个问题。@user2425142太好了。我认为最好有重点的问题。顺便说一句,欢迎光临。你可以对你觉得有用的问题和答案进行投票,也可以对你的问题进行投票。