【问题标题】:How can I accelerate processing tons of patches in a image?如何加速处理图像中的大量补丁?
【发布时间】:2019-07-19 02:47:22
【问题描述】:

我编写了一个函数来处理图像,在其中我提取了许多补丁,然后使用相同的函数(func)处理它们以生成新图像。但是,由于两个循环,func,补丁数量,补丁大小,这非常慢。我不知道如何加速这段代码。

函数如下。

# code1
def filter(img, func, ksize, strides=1):
    height,width = img.shape
    f_height,f_width = ksize
    new_height = height - f_height + 1
    new_width = width - f_width + 1

    new_img = np.zeros((new_height,new_width))

    for i in range(new_height):
        for j in range(new_width):
            patch = img[i:i+f_height,j:j+f_width]
            new_img[i][j] = func(patch)

    return new_img

func 可以非常灵活且耗时。我以一个为例。 下面的函数要计算补丁的中心点除以补丁的中位数。但是,我不希望那些值为 255 的像素计算中位数(255 是无效像素的默认值)。所以我在 numpy 中使用掩码数组。屏蔽数组使代码变慢了好几次,我不知道如何优化它。

# code2
def relative_median_and_center_diff(patch, in_the_boundary, rectangle, center_point):
        mask = patch == 255
        mask[center_point] = True
        masked_patch = np.ma.array(patch, mask=mask)
        count = masked_patch.count()
        if count <= 1:
            return 0
        else:
            return patch[center_point]/(np.ma.median(masked_patch)+1)

我尝试过或得到的想法:

  1. 我在循环之前使用了一些 numpy 函数来提取补丁,期望这可以比patch = img[i:i+f_height,j:j+f_width] 更快。我找到了从中提取补丁的功能 Extracting patches of a certain size from the image in python efficiently 起初我尝试了 skimage.util.shape 中的 view_as_windows。代码已更改,如下所示。这比 code1 需要更多的时间。我还尝试了 sklearn.feature_extraction.image.extract_patches_2d,发现这比 code3 快,但仍然比 code1 慢。(谁能告诉我为什么会这样?)
# code3
def filter(img, func, ksize, strides=1):
    height,width = img.shape
    f_height,f_width = ksize
    new_height = height - f_height + 1
    new_width = width - f_width + 1

    new_img = np.zeros((new_height,new_width))

    from skimage.util.shape import view_as_windows
    patches = view_as_windows(img, (f_height,f_width))

    for i in range(new_height):
        for j in range(new_width):
            patch = patches[i,j]
            new_img[i][j] = func(patch)

    return new_img
  1. 这个操作有点像卷积或滤波器,除了func。我想知道那些 lib 是如何处理这个问题的,你们能给我一些线索吗?

  2. 在这种情况下我们可以避免两个循环吗?也许这可以加速代码。

  3. 我有 GPU。我可以更改代码以在 gpus 上运行它并使其并行处理补丁以使其更快吗?

  4. 将代码更改为 C。这是我最不想做的事情,因为这可能有点乱。

你们能给我一些想法或建议吗?

【问题讨论】:

  • 你需要所有补丁的所有信息吗?由于我不知道这种情况,而且这几乎看起来像卷积,我们不能有步幅的概念,比如你跳过几个补丁/或将相邻补丁的平均值分配给那个补丁,这样你就可以减少正在处理的补丁数量?
  • @venkatkrishnan 感谢您的回复!我这样做是为了语义分割。所以我希望它尽可能精确。在大多数情况下,质量更重要。我将调查这种方法对质量的影响程度。再次感谢您!
  • 另外要知道,为什么每个人工作缓慢是因为他们做了很多验证检查等来提取补丁。您可以在此处将 skimage 视图的源代码视为窗口 - github.com/scikit-image/scikit-image/blob/master/skimage/util/… 和 numpy 掩码再次是一个顺序迭代过程(移动窗口类型),这显然会使其变慢。

标签: python numpy parallel-processing computer-vision image-preprocessing


【解决方案1】:

如果您的计算机有多个 CPU,您可以通过将其提交到 ThreadPoolExecutor 来多线程处理此进程

您的代码应如下所示:

from concurrent.futures import ThreadPoolExecutor
from multiprocessing import cpu_count()

executor = ThreadPoolExecutor(max_workers=cpu_count())
future = executor.submit(func, data, *args)
future_to_item[future] = data

for future in concurrent.futures.as_completed(future_to_item):
    # do something when you get the result

我一直使用 ThreadPoolExecutor 进行图像处理。

由于我们只有函数并且不知道您的程序(完全)如何工作,请查看 Python 中的并发性,以便您更好地了解如何将其集成到您的代码中:https://docs.python.org/3/library/concurrent.futures.html

【讨论】:

  • 我尝试先提取补丁,然后使用ProcessPoolExecutor 来使用多个处理器。但是,它花费了更多时间。(6s vs 0.25s)。我使用的线路是future_to_index = {executor.submit(func, patch): i for i,patch in enumerate(patches)}。也许这是因为补丁太小,不能充分利用多处理器?还是我做错了?
  • 更多代码:with concurrent.futures.ProcessPoolExecutor(max_workers=cpu_count()) as executor: future_to_index = {executor.submit(func, patch): i for i,patch in enumerate(patches)} for future in concurrent.futures.as_completed(future_to_index): i = future_to_index[future] new_img[i//new_width][i%new_width] = future.result()
  • ProcessPoolExecutorThreadPoolExecutor 大不相同。查看我附加到我的答案的链接
猜你喜欢
  • 2021-07-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-05-10
  • 2013-05-22
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多