numpy vectorize / 更高效的 for 循环

numpy vectorize / more efficient for loop

我正在对图像进行腐蚀。图像已相应填充。 简而言之,我有一个交叉元素 (+),我将其放在图像的每个像素上,并从上方、下方、右侧、左侧及其自身的像素中为该像素选择最低值。

它效率低下,我想不出矢量化版本。这一定是可能的,因为所有的计算都是相互独立的。

for y in range(t,image.shape[0]-b):
    for x in range(l,image.shape[1]-r):
        a1 = numpy.copy(str_ele)
        for filter_y in range(a1.shape[0]):
            for filter_x in range(a1.shape[1]):
                if (not (numpy.isnan(a1[filter_y][filter_x]))):
                    a1[filter_y][filter_x] = str_ele[filter_y][filter_x]*image[y+(filter_y-str_ele_center_y)][x+(filter_x-str_ele_center_x)]
        eroded_image[y][x] = numpy.nanmin(a1)   

基本上:

最终图像中的每个像素 = 原始图像的 min(pixel, above, below, left, right)

 for y in range(len(eroded_image)):
     for x in range(len(eroded_image[1])):
         eroded_image2[y][x] = numpy.nanmin(str_ele*image2[y:y+len(str_ele),x:x+(len(str_ele[1]))])

这就是我现在拥有的。还有2个循环。

如果 image 是一个用 NaN 填充的数组,并且您正在使用十字形足迹进行侵蚀, 您可以通过堆叠 image 的切片来移除 for 循环(以有效地向上、向左、向右和向下移动图像) 然后将 np.nanmin 应用于切片堆栈。

import numpy as np

def orig(image):
    t, l, b, r = 1, 1, 1, 1
    str_ele = np.array([[np.nan, 1, np.nan], [1, 1, 1], [np.nan, 1, np.nan]], dtype='float')
    str_ele_center_x, str_ele_center_y = 1, 1
    eroded_image = np.full_like(image, dtype='float', fill_value=np.nan)
    for y in range(t,image.shape[0]-b):
        for x in range(l,image.shape[1]-r):
            a1 = np.copy(str_ele)
            for filter_y in range(a1.shape[0]):
                for filter_x in range(a1.shape[1]):
                    if (not (np.isnan(a1[filter_y][filter_x]))):
                        a1[filter_y][filter_x] = str_ele[filter_y][filter_x]*image[y+(filter_y-str_ele_center_y)][x+(filter_x-str_ele_center_x)]
            eroded_image[y][x] = np.nanmin(a1)   
    return eroded_image

def erode(image):
    result = np.stack([image[1:-1, 1:-1], image[2:, 1:-1], image[:-2, 1:-1], image[1:-1, 2:], image[1:-1, :-2]])
    eroded_image = np.full_like(image, dtype='float', fill_value=np.nan)
    eroded_image[1:-1, 1:-1] = np.nanmin(result, axis=0)
    return eroded_image

image = np.arange(24).reshape(4,6)
image = np.pad(image.astype(float), 1, mode='constant', constant_values=np.nan)

产量

In [228]: erode(image)
Out[228]: 
array([[nan, nan, nan, nan, nan, nan, nan, nan],
       [nan,  0.,  0.,  1.,  2.,  3.,  4., nan],
       [nan,  0.,  1.,  2.,  3.,  4.,  5., nan],
       [nan,  6.,  7.,  8.,  9., 10., 11., nan],
       [nan, 12., 13., 14., 15., 16., 17., nan],
       [nan, nan, nan, nan, nan, nan, nan, nan]])

对于上面的小例子 imageerode 似乎比 orig 快 33 倍:

In [23]: %timeit erode(image)
10000 loops, best of 3: 35.6 µs per loop

In [24]: %timeit orig(image)
1000 loops, best of 3: 1.19 ms per loop

In [25]: 1190/35.6
Out[25]: 33.42696629213483