目标:在2D图像(灰度)中滑动2D“窗口”。对于图像的每个像素,复制窗口(图案)内的所有像素,然后移至下一个像素。
问题:非常慢。我想加快速度。
使用Cython(ewwww)除外。
我在具有48个内核的服务器中使用此代码,因此可以选择并行处理。 因此,我对如何使用numpy处理多线程解决方案感到困惑。
说明:我有一种称为提取的方法。此方法接收灰度图像,位置i和j指的是窗口居中的图像的x轴和y轴。对于i和j的每个位置,我会将窗口看到的内容复制到另一个数组。
img
是2d NumPy数组。
pat
可以删除,我可以返回该模式。没关系。
i
和j
是整数。
def extract(self, img, i, j, pat):
pattern = pat
win = self.window
hh = win.shape[0]
ww = win.shape[1]
hh2 = hh / 2
ww2 = ww / 2
k = 0
for l in range(-hh2, hh2 + 1):
for m in range(-ww2, ww2 + 1):
try:
pattern[k] = img[i + l, j + m]
except:
pattern[k] = 0
k += 1
答案 0 :(得分:1)
显而易见的答案是将这些循环矢量化。没有完整的示例,很难进行任何测试,因此我只给出一个草图。
我们要转这个:
for m in range(-ww2, ww2 + 1):
try:
pattern[k] = img[i + l, j + m]
except:
pattern[k] = 0
k += 1
…在pattern
和img
的切片上进行单个分配,而不是对pattern
和img
的索引进行循环分配。
首先,让我们忘记边界的东西,以使其更简单。我们如何才能将这些i + l
,j + m
和k
全部向量化?
m
是您范围内的索引,并且j
是常数,因此j + m
的范围超过j-ww2:j+ww2+1
。k
是您范围的索引减去范围的起始值。因此它来自ww2:2*ww2+1
。i
和l
在内部循环中都是恒定的,因此我们根本不需要在那里进行任何更改。所以:
pattern[ww2:2*ww2+1] = img[i + l, j-ww2:j+ww2+1]
现在,边界问题呢?这总是很痛苦的-在这里我无能为力,因为我不知道这些值之间如何相互关联或您担心的边界是什么,但您可能需要这样的东西:>
lok, hik = ww2, 2*ww2+1
lojm, hijm = max(0, j-ww2), min(j+ww2+1, width)
pattern[lok:hik] = img[i+l, lojm:hijm]
如果一条边的另一边需要为0,那么快速而肮脏的答案是将其手动插入,例如:
if hijm == width:
pattern[hik] = 0
一旦完成这项工作,就有望将内循环速度提高一个数量级。
如果内部循环大小适中(即ww2
不是一个很小的数字),那么您就可以完成。如果很小,您可能需要对外循环进行类似的转换,但这并不比我们刚刚做的难。