OpenCV 3.1 优化
OpenCV 3.1 optimization
我目前正在尝试使用 OpenCV 3.1 在 python 2.7 上实现一篇论文中的算法,但是这个过程花费的时间太长了。
给我带来麻烦的代码部分如下所示:
width, height = mr.shape[:2]
Pm = []
for i in d:
M = np.float32([[1,0,-d[i]], [0,1,1]])
mrd = cv2.warpAffine(mr, M, (height,width))
C = cv2.subtract(ml, mrd)
C = cv2.pow(C,2)
C = np.divide(C, sigma_m)
C = p0 + (1-p0)**(-C)
Pm.append(C)
其中ml
、mr
和mrd
是cv2对象,d
、p0
和sigma_m
是整数。
最后 3 行的除法和最终方程才是真正的麻烦制造者。这个循环的每次迭代都是独立的,所以理论上我可以通过几个处理器拆分 'for loop',但这似乎是一种懒惰的方法,我只是绕过问题而不是修复它。
有谁知道更快地执行这些计算的方法吗?
我们可以利用 numexpr
module 作为一个求值表达式有效地执行所有后面的算术运算。
因此,这些步骤:
C = cv2.subtract(ml, mrd)
C = cv2.pow(C,2)
C = np.divide(C, sigma_m)
C = p0 + (1-p0)**(-C)
可以用一个表达式代替-
import numexpr as ne
C = ne.evaluate('p0 +(1-p0)**(-((ml-mrd)**2)/sigma_m)')
让我们验证一下。原始方法为 func -
def original_app(ml, mrd, sigma_m, p0):
C = cv2.subtract(ml, mrd)
C = cv2.pow(C,2)
C = np.divide(C, sigma_m)
C = p0 + (1-p0)**(-C)
return C
验证-
In [28]: # Setup inputs
...: S = 1024 # Size parameter
...: ml = np.random.randint(0,255,(S,S))/255.0
...: mrd = np.random.randint(0,255,(S,S))/255.0
...: sigma_m = 0.45
...: p0 = 0.56
...:
In [29]: out1 = original_app(ml, mrd, sigma_m, p0)
In [30]: out2 = ne.evaluate('p0 +(1-p0)**(-((ml-mrd)**2)/sigma_m)')
In [31]: np.allclose(out1, out2)
Out[31]: True
各种大小数据集的计时 -
In [19]: # Setup inputs
...: S = 1024 # Size parameter
...: ml = np.random.randint(0,255,(S,S))/255.0
...: mrd = np.random.randint(0,255,(S,S))/255.0
...: sigma_m = 0.45
...: p0 = 0.56
...:
In [20]: %timeit original_app(ml, mrd, sigma_m, p0)
10 loops, best of 3: 67.1 ms per loop
In [21]: %timeit ne.evaluate('p0 +(1-p0)**(-((ml-mrd)**2)/sigma_m)')
100 loops, best of 3: 12.9 ms per loop
In [22]: # Setup inputs
...: S = 512 # Size parameter
In [23]: %timeit original_app(ml, mrd, sigma_m, p0)
100 loops, best of 3: 15.3 ms per loop
In [24]: %timeit ne.evaluate('p0 +(1-p0)**(-((ml-mrd)**2)/sigma_m)')
100 loops, best of 3: 3.39 ms per loop
In [25]: # Setup inputs
...: S = 256 # Size parameter
In [26]: %timeit original_app(ml, mrd, sigma_m, p0)
100 loops, best of 3: 3.65 ms per loop
In [27]: %timeit ne.evaluate('p0 +(1-p0)**(-((ml-mrd)**2)/sigma_m)')
1000 loops, best of 3: 878 µs per loop
大约 5x
各种大小的加速,较大数组的加速更快!
此外,作为旁注,我建议使用初始化的数组,而不是像您在最后一步所做的那样追加。因此,我们可以在进入循环之前用 out = np.zeros((len(d), width, height))
/ np.empty
之类的东西进行初始化,并在最后一步分配到输出数组中: out[iteration_ID] = C
.
我目前正在尝试使用 OpenCV 3.1 在 python 2.7 上实现一篇论文中的算法,但是这个过程花费的时间太长了。
给我带来麻烦的代码部分如下所示:
width, height = mr.shape[:2]
Pm = []
for i in d:
M = np.float32([[1,0,-d[i]], [0,1,1]])
mrd = cv2.warpAffine(mr, M, (height,width))
C = cv2.subtract(ml, mrd)
C = cv2.pow(C,2)
C = np.divide(C, sigma_m)
C = p0 + (1-p0)**(-C)
Pm.append(C)
其中ml
、mr
和mrd
是cv2对象,d
、p0
和sigma_m
是整数。
最后 3 行的除法和最终方程才是真正的麻烦制造者。这个循环的每次迭代都是独立的,所以理论上我可以通过几个处理器拆分 'for loop',但这似乎是一种懒惰的方法,我只是绕过问题而不是修复它。
有谁知道更快地执行这些计算的方法吗?
我们可以利用 numexpr
module 作为一个求值表达式有效地执行所有后面的算术运算。
因此,这些步骤:
C = cv2.subtract(ml, mrd)
C = cv2.pow(C,2)
C = np.divide(C, sigma_m)
C = p0 + (1-p0)**(-C)
可以用一个表达式代替-
import numexpr as ne
C = ne.evaluate('p0 +(1-p0)**(-((ml-mrd)**2)/sigma_m)')
让我们验证一下。原始方法为 func -
def original_app(ml, mrd, sigma_m, p0):
C = cv2.subtract(ml, mrd)
C = cv2.pow(C,2)
C = np.divide(C, sigma_m)
C = p0 + (1-p0)**(-C)
return C
验证-
In [28]: # Setup inputs
...: S = 1024 # Size parameter
...: ml = np.random.randint(0,255,(S,S))/255.0
...: mrd = np.random.randint(0,255,(S,S))/255.0
...: sigma_m = 0.45
...: p0 = 0.56
...:
In [29]: out1 = original_app(ml, mrd, sigma_m, p0)
In [30]: out2 = ne.evaluate('p0 +(1-p0)**(-((ml-mrd)**2)/sigma_m)')
In [31]: np.allclose(out1, out2)
Out[31]: True
各种大小数据集的计时 -
In [19]: # Setup inputs
...: S = 1024 # Size parameter
...: ml = np.random.randint(0,255,(S,S))/255.0
...: mrd = np.random.randint(0,255,(S,S))/255.0
...: sigma_m = 0.45
...: p0 = 0.56
...:
In [20]: %timeit original_app(ml, mrd, sigma_m, p0)
10 loops, best of 3: 67.1 ms per loop
In [21]: %timeit ne.evaluate('p0 +(1-p0)**(-((ml-mrd)**2)/sigma_m)')
100 loops, best of 3: 12.9 ms per loop
In [22]: # Setup inputs
...: S = 512 # Size parameter
In [23]: %timeit original_app(ml, mrd, sigma_m, p0)
100 loops, best of 3: 15.3 ms per loop
In [24]: %timeit ne.evaluate('p0 +(1-p0)**(-((ml-mrd)**2)/sigma_m)')
100 loops, best of 3: 3.39 ms per loop
In [25]: # Setup inputs
...: S = 256 # Size parameter
In [26]: %timeit original_app(ml, mrd, sigma_m, p0)
100 loops, best of 3: 3.65 ms per loop
In [27]: %timeit ne.evaluate('p0 +(1-p0)**(-((ml-mrd)**2)/sigma_m)')
1000 loops, best of 3: 878 µs per loop
大约 5x
各种大小的加速,较大数组的加速更快!
此外,作为旁注,我建议使用初始化的数组,而不是像您在最后一步所做的那样追加。因此,我们可以在进入循环之前用 out = np.zeros((len(d), width, height))
/ np.empty
之类的东西进行初始化,并在最后一步分配到输出数组中: out[iteration_ID] = C
.