用于图像处理的 cython 嵌套循环
Nested loops with cython for image processing
我正在尝试迭代包含浮点深度数据的 2D 图像,它的分辨率有点正常 (640, 480),但是 python 太慢了,所以我一直尝试使用 cython 优化问题。
我试图将循环移动到其他函数,围绕 nogil
语句移动,似乎没有用,在重新解决问题后,我能够让它的一部分工作。但是这最后一部分是无济于事的。
我试图通过事先将它们移动到 with gil
部分来从 prange()
循环中删除 python 对象,因此:
cdef int[:] w_list = array.array(range(0, w_inc, interpolation))
而不是
for r in range(0, w_inc, interpolation):
但错误仍然存在
我的代码分为两部分:
split_data()
方法将图像细分为 num
个象限,这些象限存储在 3D 数组 bits
中。这些用于将工作拆分为多个 thread/processes 更容易。这部分工作正常。
@cython.cdivision(True)
@cython.boundscheck(False)
cpdef split_data(double[:, :] frame, int h, int w, int num):
cdef double[:, :, :] bits = np.zeros(shape=(num, h // num, w // num), dtype=float)
cdef int c_count = os.cpu_count()
cdef int i, j, k
for i in prange(num, nogil=True, num_threads=c_count):
for j in prange(h // num):
for k in prange(w // num):
bits[i, j, k] = frame[i * (h // num) + j, i * (w // num) + k]
return bits
scatter_data()
方法从前面的函数中获取 bits
数组,然后创建另一个长度为 num
的 3D 数组,其中 num
是 [=23] 的长度=],称为 points
,这是表示有效深度点的一系列 3D 坐标。然后它使用 prange()
从每个 bits
中提取有效的深度数据并将它们存储到 points
@cython.cdivision(True)
@cython.boundscheck(False)
cpdef scatter_data(double[:, :] depths, object validator=None,
int h=-1, int w=-1, int interpolation=1):
# Handles if h or w is -1 (default)
if h < 0 or w < 0:
h = depths.shape[0] if h < 0 else h
w = depths.shape[1] if w < 0 else w
cdef int max_num = w * h
cdef int c_count = os.cpu_count()
cdef int h_inc = h // c_count, w_inc = w // c_count
cdef double[:, :, :] points = np.zeros(shape=(c_count, max_num, 3), dtype=float)
cdef double[:, :, :] bits = split_data(depths, h, w, c_count)
cdef int count = 0
cdef int i, r, c
cdef int[:] w_list = array.array(range(0, w_inc, interpolation))
cdef int[:] h_list = array.array(range(0, h_inc, interpolation))
for i in prange(c_count, nogil=True, num_threads=c_count):
count = 0
for r in w_list:
for c in h_list:
if depths[c, r] != 0:
points[i, count, 0] = w - r
points[i, count, 1] = c
points[i, count, 2] = depths[c, r]
count = count + 1
points = points[:count]
return points
为了完整性
3. 这是我的导入语句
import cython
from cython.parallel import prange
from cpython cimport array
import array
cimport numpy as np
import numpy as np
import os
编译代码时,我不断收到类似以下内容的错误消息:
Error compiling Cython file:
------------------------------------------------------------
...
cdef int[:] w_list = array.array(range(0, w_inc, interpolation))
cdef int[:] h_list = array.array(range(0, h_inc, interpolation))
for i in prange(c_count, nogil=True, num_threads=c_count):
count = 0
for r in w_list:
^
------------------------------------------------------------
data_util/cy_scatter.pyx:70:17: Iterating over Python object not allowed without gil
和
Error compiling Cython file:
------------------------------------------------------------
...
cdef int[:] w_list = array.array(range(0, w_inc, interpolation))
cdef int[:] h_list = array.array(range(0, h_inc, interpolation))
for i in prange(c_count, nogil=True, num_threads=c_count):
count = 0
for r in w_list:
^
------------------------------------------------------------
data_util/cy_scatter.pyx:70:17: Coercion from Python not allowed without the GIL
和
Error compiling Cython file:
------------------------------------------------------------
...
cdef int[:] w_list = array.array(range(0, w_inc, interpolation))
cdef int[:] h_list = array.array(range(0, h_inc, interpolation))
for i in prange(c_count, nogil=True, num_threads=c_count):
count = 0
for r in w_list:
^
------------------------------------------------------------
data_util/cy_scatter.pyx:70:17: Converting to Python object not allowed without gil
有办法吗?如果是这样,我该怎么做?
您只想按索引进行迭代,而不是通过 Python 迭代器进行迭代:
for ri in range(w_list.shape[0]):
r = w_list[ri]
这是 Python 中的最佳实践与 Cython 中的最佳实践不同的地方 - Cython 仅加速数字循环的迭代。您尝试这样做的方式将退回到成为一个 Python 迭代器,它既慢又需要 GIL。
我正在尝试迭代包含浮点深度数据的 2D 图像,它的分辨率有点正常 (640, 480),但是 python 太慢了,所以我一直尝试使用 cython 优化问题。
我试图将循环移动到其他函数,围绕 nogil
语句移动,似乎没有用,在重新解决问题后,我能够让它的一部分工作。但是这最后一部分是无济于事的。
我试图通过事先将它们移动到 with gil
部分来从 prange()
循环中删除 python 对象,因此:
cdef int[:] w_list = array.array(range(0, w_inc, interpolation))
而不是
for r in range(0, w_inc, interpolation):
但错误仍然存在
我的代码分为两部分:
split_data()
方法将图像细分为num
个象限,这些象限存储在 3D 数组bits
中。这些用于将工作拆分为多个 thread/processes 更容易。这部分工作正常。
@cython.cdivision(True)
@cython.boundscheck(False)
cpdef split_data(double[:, :] frame, int h, int w, int num):
cdef double[:, :, :] bits = np.zeros(shape=(num, h // num, w // num), dtype=float)
cdef int c_count = os.cpu_count()
cdef int i, j, k
for i in prange(num, nogil=True, num_threads=c_count):
for j in prange(h // num):
for k in prange(w // num):
bits[i, j, k] = frame[i * (h // num) + j, i * (w // num) + k]
return bits
scatter_data()
方法从前面的函数中获取bits
数组,然后创建另一个长度为num
的 3D 数组,其中num
是 [=23] 的长度=],称为points
,这是表示有效深度点的一系列 3D 坐标。然后它使用prange()
从每个bits
中提取有效的深度数据并将它们存储到points
@cython.cdivision(True)
@cython.boundscheck(False)
cpdef scatter_data(double[:, :] depths, object validator=None,
int h=-1, int w=-1, int interpolation=1):
# Handles if h or w is -1 (default)
if h < 0 or w < 0:
h = depths.shape[0] if h < 0 else h
w = depths.shape[1] if w < 0 else w
cdef int max_num = w * h
cdef int c_count = os.cpu_count()
cdef int h_inc = h // c_count, w_inc = w // c_count
cdef double[:, :, :] points = np.zeros(shape=(c_count, max_num, 3), dtype=float)
cdef double[:, :, :] bits = split_data(depths, h, w, c_count)
cdef int count = 0
cdef int i, r, c
cdef int[:] w_list = array.array(range(0, w_inc, interpolation))
cdef int[:] h_list = array.array(range(0, h_inc, interpolation))
for i in prange(c_count, nogil=True, num_threads=c_count):
count = 0
for r in w_list:
for c in h_list:
if depths[c, r] != 0:
points[i, count, 0] = w - r
points[i, count, 1] = c
points[i, count, 2] = depths[c, r]
count = count + 1
points = points[:count]
return points
为了完整性 3. 这是我的导入语句
import cython
from cython.parallel import prange
from cpython cimport array
import array
cimport numpy as np
import numpy as np
import os
编译代码时,我不断收到类似以下内容的错误消息:
Error compiling Cython file:
------------------------------------------------------------
...
cdef int[:] w_list = array.array(range(0, w_inc, interpolation))
cdef int[:] h_list = array.array(range(0, h_inc, interpolation))
for i in prange(c_count, nogil=True, num_threads=c_count):
count = 0
for r in w_list:
^
------------------------------------------------------------
data_util/cy_scatter.pyx:70:17: Iterating over Python object not allowed without gil
和
Error compiling Cython file:
------------------------------------------------------------
...
cdef int[:] w_list = array.array(range(0, w_inc, interpolation))
cdef int[:] h_list = array.array(range(0, h_inc, interpolation))
for i in prange(c_count, nogil=True, num_threads=c_count):
count = 0
for r in w_list:
^
------------------------------------------------------------
data_util/cy_scatter.pyx:70:17: Coercion from Python not allowed without the GIL
和
Error compiling Cython file:
------------------------------------------------------------
...
cdef int[:] w_list = array.array(range(0, w_inc, interpolation))
cdef int[:] h_list = array.array(range(0, h_inc, interpolation))
for i in prange(c_count, nogil=True, num_threads=c_count):
count = 0
for r in w_list:
^
------------------------------------------------------------
data_util/cy_scatter.pyx:70:17: Converting to Python object not allowed without gil
有办法吗?如果是这样,我该怎么做?
您只想按索引进行迭代,而不是通过 Python 迭代器进行迭代:
for ri in range(w_list.shape[0]):
r = w_list[ri]
这是 Python 中的最佳实践与 Cython 中的最佳实践不同的地方 - Cython 仅加速数字循环的迭代。您尝试这样做的方式将退回到成为一个 Python 迭代器,它既慢又需要 GIL。