使用 OpenCV 时,Cython 比 Python 慢

Cython slower compared to Python when using OpenCV

我正在试验 Cython 和 OpenCV,并尝试对图像处理的性能进行基准测试。我已尝试尽可能多地优化我的 Cython 代码,但我的性能仍然较慢。我知道由于 OpenCV,大部分代码都是在 C 中执行的,但我希望使用 Cython 的 python 循环有更好的性能。谁能告诉我是否可以做些什么来改进它?以下是我的代码:

# load_images.py

import cv2
from random import randint
import numpy as np

def fetch_images(n):
    def get_img():
        x = randint(640, 6144)
        y = randint(640, 6144)
        return np.random.rand(x,y, 3).astype(np.uint8)

    return [get_img() for _ in range(n)]

def resize_img(img):
    img = cv2.resize(img, (640, 640))
    return cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)


def preprocess(images):
    return [resize_img(img) for img in images]
# load_images_cy.pyx

import cv2
from random import randint
import numpy as np
cimport numpy as np
cimport cython
ctypedef np.uint8_t DTYPE_t

@cython.boundscheck(False)
@cython.wraparound(False)

cdef np.ndarray[DTYPE_t, ndim=3] get_img():
    cdef int x = randint(640, 6144)
    cdef int y = randint(640, 6144)
    return np.random.rand(x,y, 3).astype(np.uint8)

cpdef list fetch_images(int n):
    cdef int _;
    return [get_img() for _ in range(n)]

cdef np.ndarray[DTYPE_t, ndim=2] resize_img(np.ndarray[DTYPE_t, ndim=3] img):
    cdef np.ndarray[DTYPE_t, ndim=3] im;
    im = cv2.resize(img, (640, 640))
    return cv2.cvtColor(im, cv2.COLOR_BGR2GRAY)


cpdef np.ndarray[DTYPE_t, ndim=3] preprocess(list images):
    cdef np.ndarray[DTYPE_t, ndim=3] img;
    cdef np.ndarray[DTYPE_t, ndim=3] collection = np.empty((len(images), 640, 640), dtype=np.uint8);
    cdef int i;

    for i, img in enumerate(images):
        collection[i] = resize_img(img)

    return collection
# main.py

import load_images_cy
import load_images

import timeit

images = load_images.fetch_images(20)

result_cy = timeit.timeit(lambda: load_images_cy.preprocess(images), number=20)
result_py = timeit.timeit(lambda: load_images.preprocess(images), number=20)
print(f'{result_py/result_cy} times faster')

输出:

0.9192241989059127 times faster

Cython 主要用于与 C 代码交互,并且更容易编写 Python extension modules。虽然可以通过 Cython 获得性能改进,但它并不打算成为 Python 代码的直接加速。

然而,

PyPy 旨在为 Python 代码提供或多或少的直接加速。它提供了一个替代解释器,通常比 CPython、reference/default Python 实现更快。

此外,您的装饰师在这里:

@cython.boundscheck(False)
@cython.wraparound(False)

cdef np.ndarray[DTYPE_t, ndim=3] get_img():
    ...

仅适用于 get_img - 不适用于以下任何其他功能。不确定那是不是故意的。这些之间不能有空行。

如果您想坚持使用 Cython,并通过它获得性能改进,请考虑更改 the compilation options,例如提供 -O2-O3