Я пытаюсь перебрать 2D-изображение, содержащее данные о глубине с плавающей запятой, оно имеет несколько нормальное разрешение (640, 480), но python слишком медленный, поэтому я пытался оптимизировать проблему с помощью cython.
Я пытался переместить зацикливание на другие функции, переключив оператор nogil
, похоже, это не сработало, после переделки проблемы я смог заставить часть ее работать. Но эта последняя часть ускользает от меня напрасно.
Я попытался избавиться от объектов python из цикла prange()
, предварительно переместив их в раздел with gil
, поэтому:
cdef int[:] w_list = array.array(range(0, w_inc, interpolation))
вместо
for r in range(0, w_inc, interpolation):
но ошибка сохраняется
Мой код работает в двух частях:
- Метод
split_data()
подразделяет изображение наnum
квадрантов, которые хранятся в трехмерном массивеbits
. Они используются для упрощения разделения работы на несколько потоков/процессов. Эта часть работает нормально.
@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
из предыдущей функции, а затем создает другой 3D-массив с длинойnum
, гдеnum
— это длинаbits
, называемая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
Есть ли способ сделать это? И если да, то как мне это сделать?