有没有办法加快Python代码的速度?

有没有办法加快Python代码的速度?,python,performance,numpy,Python,Performance,Numpy,我已经编写了一些Python代码来做一些图像处理工作,但是它需要大量的时间来运行。在过去的几个小时里,我一直在尝试优化它,但我认为我已经达到了极限 从分析器的输出来看,下面的函数占用了我代码总时间的很大一部分。有什么办法可以加快速度吗 def make_ellipse(x, x0, y, y0, theta, a, b): c = np.cos(theta) s = np.sin(theta) a2 = a**2 b2 = b**2 xnew = x -

我已经编写了一些Python代码来做一些图像处理工作,但是它需要大量的时间来运行。在过去的几个小时里,我一直在尝试优化它,但我认为我已经达到了极限

从分析器的输出来看,下面的函数占用了我代码总时间的很大一部分。有什么办法可以加快速度吗

def make_ellipse(x, x0, y, y0, theta, a, b):
    c = np.cos(theta)
    s = np.sin(theta)
    a2 = a**2
    b2 = b**2
    xnew = x - x0
    ynew = y - y0
    ellipse = (xnew * c + ynew * s)**2/a2 + (xnew * s - ynew * c)**2/b2 <= 1

    return ellipse
def make_椭圆(x,x0,y,y0,θ,a,b):
c=np.cos(θ)
s=np.sin(θ)
a2=a**2
b2=b**2
xnew=x-x0
ynew=y-y0

椭圆=(xnew*c+ynew*s)**2/a2+(xnew*s-ynew*c)**2/b2使用Cython可以大大加快速度。关于如何做到这一点,有一个非常好的文档。

让我们尝试与调用者一起优化make_ellipse

首先,请注意,
a
b
在许多调用中是相同的。由于make_椭圆每次都会对其进行平方运算,因此只需让调用者这样做即可

其次,请注意,
np.cos(np.arctan(theta))
1/np.sqrt(1+theta**2)
,在我的系统上似乎稍微快一点。可以使用类似的技巧从θ或cos(θ)计算正弦(反之亦然)


第三,更具体地说,考虑缩短一些最终椭圆公式的计算。例如,如果
(xnew*c+ynew*s)**2/a2
大于1,则椭圆值必须为False。如果这种情况经常发生,您可以在这些位置“屏蔽”椭圆(昂贵)计算的后半部分。我还没有完全计划好这一点,但请参阅numpy.ma以了解一些可能的线索。

它不会在所有情况下加快速度,但如果椭圆没有占据整个图像,则应将椭圆内点的搜索限制在其边界矩形内。我对数学很懒惰,所以我重新使用了反正切技巧的@JohnZwinck-neat-cosine来实现这个函数:

def ellipse_bounding_box(x0, y0, theta, a, b):
    x_tan_t = -b * np.tan(theta) /  a
    if np.isinf(x_tan_t) :
        x_cos_t = 0
        x_sin_t = np.sign(x_tan_t)
    else :
        x_cos_t = 1 / np.sqrt(1 + x_tan_t*x_tan_t)
        x_sin_t = x_tan_t * x_cos_t
    x = x0 + a*x_cos_t*np.cos(theta) - b*x_sin_t*np.sin(theta)

    y_tan_t = b / np.tan(theta) /  a
    if np.isinf(y_tan_t):
        y_cos_t = 0
        y_sin_t = np.sign(y_tan_t)
    else:
        y_cos_t = 1 / np.sqrt(1 + y_tan_t*y_tan_t)
        y_sin_t = y_tan_t * y_cos_t
    y = y0 + b*y_sin_t*np.cos(theta) + a*y_cos_t*np.sin(theta)

    return np.sort([-x, x]), np.sort([-y, y])
现在,您可以将原始函数修改为以下内容:

def make_ellipse(x, x0, y, y0, theta, a, b):
    c = np.cos(theta)
    s = np.sin(theta)
    a2 = a**2
    b2 = b**2
    x_box, y_box = ellipse_bounding_box(x0, y0, theta, a, b)
    indices = ((x >= x_box[0]) & (x <= x_box[1]) & 
               (y >= y_box[0]) & (y <= y_box[1]))
    xnew = x[indices] - x0
    ynew = y[indices] - y0
    ellipse = np.zeros_like(x, dtype=np.bool)
    ellipse[indices] = ((xnew * c + ynew * s)**2/a2 +
                        (xnew * s - ynew * c)**2/b2 <= 1)
    return ellipse
def make_椭圆(x,x0,y,y0,θ,a,b):
c=np.cos(θ)
s=np.sin(θ)
a2=a**2
b2=b**2
x_盒,y_盒=椭圆_边界_盒(x0,y0,θ,a,b)

索引=((x>=x_-box[0])&(x=y_-box[0])&(y因为除了x和y以外的所有东西都是整数,所以可以尝试最小化数组计算的数量。我想大部分时间都花在这条语句中:

ellipse = (xnew * c + ynew * s)**2/a2 + (xnew * s - ynew * c)**2/b2 <= 1

椭圆=(xnew*c+ynew*s)**2/a2+(xnew*s-ynew*c)**2/b2我正在测试此例程的性能,并且我有良好的性能…1.37s,图像为4000x4000。参数:x=邻域空间(0,14000);x,Y=网格(x,x);使\u椭圆(x、0、Y、0、1、1、1)。您确定它是最慢的吗?您可以使用
np.ogrid
np.meshgrid(…,sparse=True)
为您的输入创建一个稀疏的正交网格
x
y
坐标。这节省了一些内存,并在
make_ellipse
中为您提供了一个小的性能增益。文档在哪里?@JohnZwinck是其中之一,我想。不过,我自己研究Cython已经好几年了;我刚进入Python的时候Rpython3问世了,当时没有多少第三方支持,包括Cython(如果我没记错的话,至少是这样)。代码除了调用numpy几次之外什么也不做,OP已经尝试了numba,但都没有成功。为什么Cython的表现会更好呢?似乎算法太慢了。numpy.ma不是速度恶魔。使用if!
ellipse=False if(xnew*c+ynew*s)**2/a2>1 else(xnew*c+ynew*s)**2/a2+(xnew*s-ynew*c)**2/b2我现在不太喜欢它,因为它会导致第一部分执行两次。我会将我的建议修改为
first\u part=(xnew*c+ynew*s)**2/a2
eliple=False if first\u part>1 else first\u part+(xnew*s-ynew*c)**2/b2
a = float(a)
b = float(b)
ellipse = (xnew * (c/a) + ynew * (s/a))**2 + (xnew * (s/b) - ynew * (c/b))**2 <= 1
ellipse = ((xnew + ynew * (s/c)) * (c/a))**2 + ((xnew * (s/c) - ynew) * (c/b))**2 <= 1
t = numpy.tan(theta)
ellipse = ((xnew + ynew * t) * (b/a))**2 + (xnew * t - ynew)**2 <= (b/c)**2