编辑我保留了下面所面临的更复杂的问题,但是我的问题可以更好地总结如下。假设您有一个shapenp.take
的数组,另一个shapeimg
的数组,您希望使用它们创建shape(planes, rows)
的新数组,其中lut
。这可以通过以下花式索引实现:
In [4]: %timeit lut[np.arange(planes).reshape(-1, 1), img]
1000 loops, best of 3: 471 us per loop
但是,如果使用take和python循环而不是花哨的索引,那么可以极大地加快
(planes, 256)
的速度:In [6]: %timeit for _ in (lut[j].take(img[j]) for j in xrange(planes)) : pass
10000 loops, best of 3: 59 us per loop
是否可以以某种方式重新排列
out
和(planes, rows)
以使整个操作在没有python循环的情况下发生,但使用out[p,j] = lut[p, img[p, j]]
(或其他方法)而不是传统的花式索引来保持速度优势?原始问题
我有一组查找表(LUT),要在图像上使用。保存LUT的数组的形状为
planes
,图像的形状为lut
。两者均为img
,与LUT的numpy.take
轴匹配。其思想是从LUT的第n个平面通过每个LUT运行图像的第n个平面。如果my
(planes, 256, n)
和(planes, rows, cols)
如下:planes, rows, cols, n = 3, 4000, 4000, 4
lut = np.random.randint(-2**31, 2**31 - 1,
size=(planes * 256 * n // 4,)).view('uint8')
lut = lut.reshape(planes, 256, n)
img = np.random.randint(-2**31, 2**31 - 1,
size=(planes * rows * cols // 4,)).view('uint8')
img = img.reshape(planes, rows, cols)
我可以在使用这种花哨的索引之后实现我现在的目标
out = lut[np.arange(planes).reshape(-1, 1, 1), img]
这给了我一个形状数组,其中包含了通过lut的第n个平面的第n个lut的第n个lut的第n个平面。
除此之外,一切都很好:
In [2]: %timeit lut[np.arange(planes).reshape(-1, 1, 1), img]
1 loops, best of 3: 5.65 s per loop
这是完全不可接受的,尤其是我有以下所有不好看的选择,使用
dtype = 'uint8'
比运行快得多:单个平面上的单个LUT运行速度约为X70:
In [2]: %timeit np.take(lut[0, :, 0], img[0])
10 loops, best of 3: 78.5 ms per loop
在所有需要的组合中运行的python循环可以更快地完成X6:
In [2]: %timeit for _ in (np.take(lut[j, :, k], img[j]) for j in xrange(planes) for k in xrange(n)) : pass
1 loops, best of 3: 947 ms per loop
即使运行LUT和图像中的所有平面组合,然后丢弃不需要的平面也比花式索引快:
In [2]: %timeit np.take(lut, img, axis=1)[np.arange(planes), np.arange(planes)]
1 loops, best of 3: 3.79 s per loop
我能想到的最快的组合是在平面上迭代一个python循环并更快地完成x13:
In [2]: %timeit for _ in (np.take(lut[j], img[j], axis=0) for j in xrange(planes)) : pass
1 loops, best of 3: 434 ms per loop
当然,问题是,如果没有任何python循环,就无法使用
256
执行此操作吗?理想情况下,无论需要什么整形或调整大小都应该发生在LUT上,而不是图像上,但我愿意接受任何你可以想到的… 最佳答案
首先,我必须说我真的很喜欢你的问题。在不重新排列LUT
或IMG
的情况下,以下解决方案起作用:
%timeit a=np.take(lut, img, axis=1)
# 1 loops, best of 3: 1.93s per loop
但从结果中,您必须查询对角线:a[0,0]、a[1,1]、a[2,2];才能得到您想要的。我试图找到一种方法,只对对角线元素进行索引,但仍然没有成功。
以下是重新排列您的
LUT
和IMG
的一些方法:如果
IMG
中的索引为0-255,对于第一个平面,256-511对于第二个平面,512-767对于第三个平面,则以下内容适用,但这将阻止您使用'uint8'
,这可能是一个大问题…:lut2 = lut.reshape(-1,4)
%timeit np.take(lut2,img,axis=0)
# 1 loops, best of 3: 716 ms per loop
# or
%timeit np.take(lut2, img.flatten(), axis=0).reshape(3,4000,4000,4)
# 1 loops, best of 3: 709 ms per loop
在我的机器中,您的解决方案仍然是最佳选择,而且非常充分,因为您只需要对角评估,即plane1-plane1、plane2-plane2和plane3-plane3:
%timeit for _ in (np.take(lut[j], img[j], axis=0) for j in xrange(planes)) : pass
# 1 loops, best of 3: 677 ms per loop
我希望这能给你一些更好的解决方案的见解。如果能用
flatten()
和类似于np.apply_over_axes()
或np.apply_along_axis()
的方法来寻找更多的选项,这将是一个不错的选择。我使用下面的代码生成数据:
import numpy as np
num = 4000
planes, rows, cols, n = 3, num, num, 4
lut = np.random.randint(-2**31, 2**31-1,size=(planes*256*n//4,)).view('uint8')
lut = lut.reshape(planes, 256, n)
img = np.random.randint(-2**31, 2**31-1,size=(planes*rows*cols//4,)).view('uint8')
img = img.reshape(planes, rows, cols)
关于python - 使用numpy.take进行更快速的花式索引,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/14491480/