【发布时间】:2019-03-03 05:28:54
【问题描述】:
我有一些 Cython 代码,涉及对以下形式的 Numpy 数组(表示 BGR 图像)进行极其重复的逐像素操作:
ctypedef double (*blend_type)(double, double) # function pointer
@cython.boundscheck(False) # Deactivate bounds checking
@cython.wraparound(False) # Deactivate negative indexing.
cdef cnp.ndarray[cnp.float_t, ndim=3] blend_it(const double[:, :, :] array_1, const double[:, :, :] array_2, const blend_type blendfunc, const double opacity):
# the base layer is a (array_1)
# the blend layer is b (array_2)
# base layer is below blend layer
cdef Py_ssize_t y_len = array_1.shape[0]
cdef Py_ssize_t x_len = array_1.shape[1]
cdef Py_ssize_t a_channels = array_1.shape[2]
cdef Py_ssize_t b_channels = array_2.shape[2]
cdef cnp.ndarray[cnp.float_t, ndim=3] result = np.zeros((y_len, x_len, a_channels), dtype = np.float_)
cdef double[:, :, :] result_view = result
cdef Py_ssize_t x, y, c
for y in range(y_len):
for x in range(x_len):
for c in range(3): # iterate over BGR channels first
# calculate channel values via blend mode
a = array_1[y, x, c]
b = array_2[y, x, c]
result_view[y, x, c] = blendfunc(a, b)
# many other operations involving result_view...
return result;
其中blendfunc指的是另一个cython函数,比如下面的overlay_pix:
cdef double overlay_pix(double a, double b):
if a < 0.5:
return 2*a*b
else:
return 1 - 2*(1 - a)*(1 - b)
使用函数指针的目的是避免为每种混合模式(其中有很多)一遍又一遍地重写大量重复的代码。因此,我为每种混合模式创建了一个这样的界面,省去了我的麻烦:
def overlay(double[:, :, :] array_1, double[:, :, :] array_2, double opacity = 1.0):
return blend_it(array_1, array_2, overlay_pix, opacity)
但是,这似乎花费了我一些时间!我注意到,对于非常大的图像(例如 8K 和更大的图像),在 blend_it 函数中使用 blendfunc 而不是在 blend_it 中直接调用 overlay_pix 会浪费大量时间。我认为这是因为blend_it 在迭代中每次都必须取消引用函数指针,而不是让函数立即可用,但我不确定。
时间损失并不理想,但我当然不想为每种混合模式一遍又一遍地重写blend_it。有什么方法可以避免时间损失吗?有没有办法将函数指针变成循环外的本地函数,然后在循环内更快地访问它?
【问题讨论】:
标签: python function numpy pointers cython