简体   繁体   English

沿2D数组滑动子数组

[英]Sliding a subarray along a 2d array

This is something I've been struggling with for a couple of weeks. 这是我一直努力奋斗的事情。 The algorithm is the following: 该算法如下:

  1. Select a subarray as an array of rows and columns from a larger array 从更大的数组中选择一个子数组作为行和列的数组
  2. Compute the median of the subarray 计算子数组的中位数
  3. Replace cells in subarray with median value 用中值替换子数组中的单元格
  4. Move the subarray to the right by its own length 将子数组向右移动自己的长度
  5. Repeat to end of array 重复到数组末尾
  6. Move subarray down by its own height 将子数组向下移动自己的高度
  7. Repeat 重复

I've got steps 1 to 3 as follows: 我有步骤1到3,如下所示:

import numpy as np
w1 = np.arange(100).reshape(10,10)
side = 3
patch = w1[0:side, 0:side]

i, j = patch.shape
for j in range(side):
    for i in range(side):
        patch[i,j] = np.median(patch)

Eventually, I'll be using a 901x877 array from an image but I'm just trying to get a hold of this simple task first. 最终,我将使用图像中的901x877阵列,但我只是想首先抓住这个简单的任务。 How can I slide the array along and then down with a loop? 我如何才能使数组前后滑动并向下循环?

Here are a few "code smells" I see. 我看到了一些“代码气味”。 Start with the range(side) since this number is set to 3 then you are going to have a result of [0,1,2] . 因为这个数字设置为3所以从range(side)开始,您将得到[0,1,2]的结果。 Is that what you really want? 那是你真正想要的吗?

you set i,j = patch.size then immediately over write these values, in your for loops. 您设置i,j = patch.size然后在您的for循环中立即覆盖这些值。

Finally, you're recalculating median every loop. 最后,您要重新计算每个循环的median

Ok, here's what I'd do. 好的,这就是我要做的。

  1. figure out how many patches you'll need in both width and height. 找出在宽度和高度上需要多少个补丁。 and multiply those by the size of the side. 并乘以边的大小。
  2. slice your array (matrix) up into those pieces. 将您的数组(矩阵)切成碎片。
  3. assign the patch to the median. 将补丁分配给中位数。

import numpy as np                                                                                                                                                                                         
w1 = np.arange(100).reshape(10,10)                                                                                                                                                                         
side = 3                                                                                                                                                                                                   
w, h = w1.shape                                                                                                                                                                                            
width_index   = np.array(range(w//side)) * side                                                                                                                                                             
height_index  = np.array(range(h//side)) * side                                                                                                                                                             

def assign_patch(patch, median, side):                                                                                                                                                                     
    """Break this loop out to prevent 4 nested 'for' loops"""                                                                                                                                              
    for j in range(side):                                                                                                                                                                                  
        for i in range(side):                                                                                                                                                                              
            patch[i,j] = median                                                                                                                                                                            
    return patch                                                                                                                                                                                           

for width in width_index:                                                                                                                                                                                  
    for height in height_index:                                                                                                                                                                            
        patch  = w1[width:width+side, height:height+side]                                                                                                                                                  
        median = np.median(patch)                                                                                                                                                                          
        assign_patch(patch, median, side)                                                                           

print w1        

You can use scikit-image's view_as_blocks and NumPy broadcasting to vectorize the operation: 您可以使用scikit-image的view_as_blocks和NumPy广播对操作进行矢量化处理:

import numpy as np
import skimage

w1 = np.arange(144).reshape(12,12)
print(w1)
# [[  0   1   2   3   4   5   6   7   8   9  10  11]
#  [ 12  13  14  15  16  17  18  19  20  21  22  23]
#  [ 24  25  26  27  28  29  30  31  32  33  34  35]
#  [ 36  37  38  39  40  41  42  43  44  45  46  47]
#  [ 48  49  50  51  52  53  54  55  56  57  58  59]
#  [ 60  61  62  63  64  65  66  67  68  69  70  71]
#  [ 72  73  74  75  76  77  78  79  80  81  82  83]
#  [ 84  85  86  87  88  89  90  91  92  93  94  95]
#  [ 96  97  98  99 100 101 102 103 104 105 106 107]
#  [108 109 110 111 112 113 114 115 116 117 118 119]
#  [120 121 122 123 124 125 126 127 128 129 130 131]
#  [132 133 134 135 136 137 138 139 140 141 142 143]]

side = 3
w2 = skimage.util.view_as_blocks(w1, (side, side))
w2[...] = np.median(w2, axis=(-2, -1))[:, :, None, None]
print(w1)
# [[ 13  13  13  16  16  16  19  19  19  22  22  22]
#  [ 13  13  13  16  16  16  19  19  19  22  22  22]
#  [ 13  13  13  16  16  16  19  19  19  22  22  22]
#  [ 49  49  49  52  52  52  55  55  55  58  58  58]
#  [ 49  49  49  52  52  52  55  55  55  58  58  58]
#  [ 49  49  49  52  52  52  55  55  55  58  58  58]
#  [ 85  85  85  88  88  88  91  91  91  94  94  94]
#  [ 85  85  85  88  88  88  91  91  91  94  94  94]
#  [ 85  85  85  88  88  88  91  91  91  94  94  94]
#  [121 121 121 124 124 124 127 127 127 130 130 130]
#  [121 121 121 124 124 124 127 127 127 130 130 130]
#  [121 121 121 124 124 124 127 127 127 130 130 130]]

Note that I had to change the size of your array to 12x12 so that all of your tiles of 3x3 actually fit in there. 请注意,我必须将数组的大小更改为12x12以便所有3x3的图块实际上都适合其中。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM