2013-05-27 44 views
13

尝试将尺寸为100x100的灰度图像切片为尺寸为39x39且重叠的补丁,尺寸为1.这意味着将开始下一个补丁向右/向下的一个像素仅与一个附加的列/行中的先前的修补程序不同。将图片切片成重叠的补丁并将补丁合并到图像的快速方法

代码的粗糙的轮廓:首先计算每个补丁的索引,所以能够 从图像构造贴剂的2D阵列,并能够从贴剂构建图像:

patches = imgFlat[ind] 

'patches'是一个2D数组,每列包含一个矢量形式的补丁。

对这些补丁进行处理,每个补丁单独和之后再次与预先计算的索引合并为一个图像。

img = np.sum(patchesWithColFlat[ind],axis=2) 

补丁程序重叠,它是在结束必要的预先计算的权重乘以IMG:

imgOut = weights*imgOut 

我的代码是很慢和速度是一个关键问题,因为这应该是上完成约10^8个补丁。

函数get_indices_for_un_patchify和weights_unpatchify可以预先计算一次,所以速度只是修补和未修补的问题。

感谢您的任何提示。

卡洛斯

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()) 
+0

你有什么需要的补丁呢?也许整个事情可以作为一个卷积来完成。您的'patchify'功能可以通过虚幻的方式完成,可以随着步伐自由地玩耍,但我不确定它的反面。 – jorgeca

+0

补丁用于训练神经网络.100x100图像被切成39x39的补丁。这些补丁被输入神经网络。然后将神经网络(也包括补丁)的输出合并在一起以再次获得100x100(或更小的)图像。这必须用不同的100x100图像多次完成。所以我真的很感兴趣,你觉得如何加快修补功能,“免费”呢? – user2425142

+0

为什么你不使用scikit的'从2D功能提取补丁'?它只提供重叠的补丁。对于重建来说,“从补丁2d'重建功能。 – user3515225

回答

15

一种有效的方式来“patchify”的阵列,即,以获得窗口阵列到原来的阵列是创建定制strides的视图,字节数跳转到以下元素。将numpy数组视为一个(荣耀的)内存块可能会有所帮助,然后跨步是将索引映射到内存地址的一种方法。

例如,在

a = np.arange(10).reshape(2, 5) 

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 

事实上,这些元件被放置在存储器接二连三,0 1 2 3 4 5 6 7 x x但步幅让我们以二维数组为索引。对这一概念

基础上,我们可以重写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) 

该函数返回的img视图,所以没有分配内存,并在短短的几十微秒运行。输出形状并不完全是你想要的,事实上它必须被复制才能得到那个形状。

当处理比基本数组大得多的数组视图时,必须小心,因为操作可能会触发需要分配大量内存的副本。在你的情况下,由于阵列不是太大,并没有那么多的补丁,它应该没问题。

最后,我们可以拆开贴片阵列位:

patches = patchify(img, (39,39)) 
contiguous_patches = np.ascontiguousarray(patches) 
contiguous_patches.shape = (-1, 39**2) 

这不会重现您patchify函数的输出,因为你种的开发Fortran语言秩序的修补程序。我建议你这不是因为

  1. 它会导致更多的自然索引以后使用(即第一个补丁是补丁[0],而不是补丁[:,0]您的解决方案)。

  2. 在numpy中,随处使用C排序也比较容易,因为您需要更少的输入(避免使用order ='F',数组默认情况下按C顺序创建...)。

万一

“提示”您坚持:strides = img.itemsize * np.array([1, Y, Y, 1]),在contiguous_patches使用.reshape(..., order='F')最后转它.T

+1

非常感谢。从python的回答中学到了很多东西。 @joregca:真的超级快。我会做功课:)并用Fortran命令发布解决方案。对于那些不明白张贴的答案马上(我没有),看看帮助(np.lib.stride_tricks.as_strided)和[另一个问题在stackoverflow](http://stackoverflow.com/questions/8070349/using-numpy-stride-tricks-to-get-non-overlapping-array-blocks)了解更多关于stride_tricks的信息。 – user2425142

+0

但任何人有一个想法如何使unpatchify函数更快? – user2425142

+0

@ user2425142我扩大了我的答案,我希望现在更清楚。不过,我没有类似的解决方案来解决逆向问题。我不确定将这两个问题放在一起还是应该将它们分开。 – jorgeca