【问题标题】:What is the best way to iterate over numpy 2d array by NxN frame for filtering image?通过NxN帧迭代numpy 2d数组以过滤图像的最佳方法是什么?
【发布时间】:2019-03-09 11:53:15
【问题描述】:

有一个简单的模糊滤镜,可以计算周围的明暗像素。这是代码。但是我的实现相当慢(780x1200 阵列大约需要 3 秒)。当然可以更快

import time
import numpy as np
from skimage.data import imread

def _filter_step(in_img, out_img, n, pos=(0,0)):
    y = (pos[0] - n//2, pos[0]+n//2+1)     # frame borders
    x = (pos[1] - n//2, pos[1]+n//2+1)

    frame = in_img[y[0]:y[1],  x[0]:x[1]]  # get frame

    whites = np.count_nonzero(frame)       # count light pixels
    k = whites/(n*n)                       # calculate proportion
    out_img[pos[0], pos[1]] = int(k * 255) # write new pixel


def make_filter(img, n):
    if not n % 2:
        raise ValueError("n must be odd")
    img = img > 180                        # binarize 

    out_img = np.empty_like(img)           # output array

    for i in range(img.shape[0]):
        for j in range(img.shape[1]):
            _filter_step(img, out_img, n, (i, j))
    return out_img

if __name__ == "__main__":
    image = imread("img780x1200.jpg", as_gray=True) 
    n = 11
    time_start = time.time()
    image1 = make_filter(image, n)
    print(time.time() - time_start) # ~3 sec

我尝试并行计算:

import multiprocessing as mp
import ctypes as ct

def iter_image(x1, y1, x2, y2, img, out_img, n, mode=0):
    out_img = np.frombuffer(out_img, dtype=ct.c_int).reshape(img.shape)
    for y in range(img.shape[0])[::(-1)**mode]:
        for x in range(img.shape[1])[::(-1)**mode]:
            if mode:
                y2.value, x2.value = y, x
            else:
                y1.value, x1.value = y, x

            if y1.value < y2.value or x1.value < x2.value:
                _filter_step(img, out_img, n, ((y1.value,x1.value), (y2.value,x2.value))[mode])
            else:
                return ((y1, x1), (y2, x2))[mode]
    return ((y1, x1), (y2, x2))[mode]


def mp_make_filter(img, n):
    if not n % 2:
        raise ValueError("n must be odd")

    img = img > 180

    x1 = mp.Value('i', 0, lock=False)
    y1 = mp.Value('i', 0, lock=False)
    x2 = mp.Value('i', 0, lock=False)
    y2 = mp.Value('i', 0, lock=False)
    out_img = mp.Array('i', np.empty(img.shape[0] * img.shape[1], dtype=ct.c_int), lock=False)

    p1 = mp.Process(target=iter_image, args=(x1, y1, x2, y2, img, out_img, n, 0))
    p2 = mp.Process(target=iter_image, args=(x1, y1, x2, y2, img, out_img, n, 1))

    p1.start()
    p2.start()
    p1.join()
    p2.join()

    return np.frombuffer(out_img, dtype=ct.c_int).reshape(img.shape)

此代码在 2 个线程中迭代数组,而它们彼此不“相遇”。但它使性能更慢(大约 5 秒) 如何加快代码速度?

【问题讨论】:

    标签: python performance numpy blur scikit-image


    【解决方案1】:

    首先,您的窗口代码中有一个小错误。您需要在零处剪辑,因为负索引会环绕。

        y = (max(pos[0] - n//2, 0), pos[0]+n//2+1)     # frame borders
        x = (max(pos[1] - n//2, 0), pos[1]+n//2+1)
    

    此外,您可能希望在将 img 设为布尔数组之前将 out_img = np.empty_like(img) 行移至。

    这是使用cumsum 的更快方法:

    y, x = image.shape
    padded = np.zeros((y+k, x+k), 'i1')
    padded[k//2+1:-k//2+1, k//2+1:-k//2+1] = image > 180
    dint = padded.cumsum(1).cumsum(0)
    result = dint[k:, k:] + dint[:-k, :-k] - dint[k:, :-k] - dint[:-k, k:]
    result = (result * 255 / (k*k)).astype('u1')
    

    【讨论】:

    • 非常感谢。它快 30 倍,完全满意。你能解释一下这种棘手方法的想法吗?这是一种传承魔法吗?
    • 我将在一维中解释:我们所做的本质上是一个滑动总和。 S_k = a_k + a_{k+1} + ... +a_{k+w-1}。如果你“天真”地这样做,S 的每个元素都会花费 w-1 加法,所以总成本大约是 Nw。相反,如果我们形成所有部分和 A_1 = a_1、A_2 = A_1 + a_2、A_3 = A_2 + a_3 等,那么我们可以得到 S_k = A_{k+w-1} ​​- A_{k-1},即 a单减法。因此,总成本约为 2N。
    猜你喜欢
    • 2017-03-28
    • 1970-01-01
    • 1970-01-01
    • 2011-01-20
    • 2018-06-01
    • 2021-07-10
    • 2010-10-07
    • 1970-01-01
    相关资源
    最近更新 更多