循环计算的python性能提示

2024-03-29 08:24:40 发布

您现在位置:Python中文网/ 问答频道 /正文

Python2.7和Windows7。你知道吗

我正在寻找如何快速计算脚本。首先是我的想法:

从一个给定的颜色开始,我想生成一个由30种以上的颜色(rgb值)组成的列表,这些颜色对于人眼来说彼此之间的区别最大,并且列表的前面比末尾更明显。你知道吗

目前,我估计这个脚本需要48小时才能完成。我可以让它在周末运行,但我想我会借此机会学习一些关于python性能的知识。你知道吗

概述代码的作用:

gen_colours()包含一个运行30次的循环。每次有4个进程运行multi(n, l, g),其中包含在0和255之间的r、g和b值上迭代的大循环(r值在进程之间被分割,因此它循环64次)。最内部的循环包含另一个循环,该循环将rgb值与通过调用compute_dist([r, g, b], c)找到的rgb值进行检查。你知道吗

不管怎样,如果不完全重组我的代码,帮助它加速的东西会很酷。另外,运行所有四个CPU最多48小时…有问题吗?你知道吗

代码:

from math import sqrt, pow, atan2, atan, sin, cos, exp, radians, degrees
from fractions import Fraction
import time
import multiprocessing


def to_xyz(rgb):
    r = rgb[0] / 255.0
    g = rgb[1] / 255.0
    b = rgb[2] / 255.0

    f = Fraction(12, 5)

    if r > 0.04045:
        r = ((r + 0.055) / 1.055) ** f
    else:
        r /= 12.92
    if g > 0.04045:
        g = ((g + 0.055) / 1.055) ** f
    else:
        g /= 12.92
    if b > 0.04045:
        b = ((b + 0.055) / 1.055) ** f
    else:
        b /= 12.92

    r *= 100
    g *= 100
    b *= 100

    # Observer = 2 degrees, Illuminant = D65
    x = r * 0.4124 + g * 0.3576 + b * 0.1805
    y = r * 0.2126 + g * 0.7152 + b * 0.0722
    z = r * 0.0193 + g * 0.1192 + b * 0.9505

    return [x, y, z]


def to_lab(xyz):

    x = xyz[0]
    y = xyz[1]
    z = xyz[2]

    # Observer= 2deg, Illuminant= D65
    x /= 95.047
    y /= 100.0
    z /= 108.883

    f = Fraction(1, 3)

    if x > 0.008856:
        x **= f
    else:
        x = 7.787 * x + 0.13793103448
    if y > 0.008856:
        y **= f
    else:
        y = 7.787 * y + 0.13793103448
    if z > 0.008856:
        z **= f
    else:
        z = 7.787 * z + 0.13793103448

    L = 116 * y - 16
    a = 500 * (x - y)
    b = 200 * (y - z)

    return [L, a, b]


def compute_dist(rgb1, rgb2):
    """ Compute the apparent difference in colours using CIEDE2000 standards """

    xyz1 = to_xyz(rgb1)
    xyz2 = to_xyz(rgb2)

    lab1 = to_lab(xyz1)
    lab2 = to_lab(xyz2)

    a1 = lab1[1]
    a2 = lab2[1]
    b1 = lab1[2]
    b2 = lab2[2]
    L1 = lab1[0]
    L2 = lab2[0]

    c1 = sqrt(a1 * a1 + b1 * b1)
    c2 = sqrt(a2 * a2 + b2 * b2)
    c = (c1 + c2) / 2
    crs = c ** 7
    x = 0.5 - 0.5 * sqrt(crs / (crs + 6103515625))
    temp = (1 + x) * a1
    c1 = sqrt(temp * temp + b1 * b1)
    h1 = hue(temp, b1)
    temp = (1 + x) * a2
    c2 = sqrt(temp * temp + b2 * b2)
    h2 = hue(temp, b2)
    dL = L2 - L1
    dc = c2 - c1
    if c1 * c2 == 0:
        dh = 0
    else:
        temp = round(h2 - h1, 12)
        if abs(temp) <= 180:
            dh = h2 - h1
        else:
            if temp > 180:
                dh = h2 - h1 - 360
            else:
                dh = h2 - h1 + 360
    dh = sqrt(c1 * c2) * sin(radians(dh / 2))
    dh += dh
    lav = (L1 + L2) / 2
    cav = (c1 + c2) / 2
    if c1 * c2 == 0:
       htot = h1 + h2
    else:
        temp = abs(round(h1 - h2, 12))
        if temp > 180:
            if h2 + h1 < 360:
                htot = h1 + h2 + 360
            else:
                htot = h1 + h2 - 360
        else:
            htot = h1 + h2
        htot /= 2

    T = 1 - 0.17 * cos(radians(htot - 30)) + 0.24 * cos(radians(2 * htot)) + 0.32 * cos(radians(3 * htot + 6)) - 0.20 * cos(radians(4 * htot - 63))
    htotdtme = (htot / 25) - 11
    xPH = 30 * exp(-htotdtme * htotdtme)
    cavrs = cav ** 7
    scocp = sqrt(cavrs / (cavrs + 6103515625))
    xRC = scocp + scocp
    lavmf = lav - 50
    lavmfs = lavmf * lavmf
    SL = 1 + 0.015 * lavmfs / sqrt(20 + lavmfs)
    SC = 1 + 0.045 * cav
    SH = 1 + 0.015 * cav * T
    RT = -sin(radians(xPH + xPH)) * xRC
    dL /= SL
    dc /= SC
    dh /= SH
    dE = sqrt(dL * dL + dc * dc + dh * dh + RT * dc * dh)

    return dE


def hue(a, b):          # Function returns CIELAB-Hue value

    c = 0
    if a >= 0 and b == 0:
        return 0
    if a < 0 and b == 0:
        return 180
    if a == 0 and b > 0:
        return 90
    if a == 0 and b < 0:
        return 270
    if a > 0 and b > 0:
        c = 0
    elif a < 0:
        c = 180
    elif b < 0:
        c = 360
    return degrees(atan(b / a)) + c


def multi(p, l, q):
    f = 0
    n = []

    s = p * 64
    e = (p + 1) * 64
    for r in xrange(s, e):
        for g in xrange(256):
            for b in xrange(256):
                s = 1000  # smallest dist

                for c in l:  # compare to existing colours

                    d = compute_dist([r, g, b], c)
                    if d < s:
                        s = d

                if s > f:
                    n = [r, g, b]
                    f = s

    q.put(f)
    q.put(n)


def gen_colours(start_col=[68, 68, 68]):

    out = open('colour_output.txt', 'w')
    l = [start_col]

    if __name__ == '__main__':

        q0 = multiprocessing.Queue()
        q1 = multiprocessing.Queue()
        q2 = multiprocessing.Queue()
        q3 = multiprocessing.Queue()

        for h in xrange(30):  # create 30 more colours

            p0 = multiprocessing.Process(target=multi, args=[0, l, q0])
            p1 = multiprocessing.Process(target=multi, args=[1, l, q1])
            p2 = multiprocessing.Process(target=multi, args=[2, l, q2])
            p3 = multiprocessing.Process(target=multi, args=[3, l, q3])

            p0.start()
            p1.start()
            p2.start()
            p3.start()

            p0.join()
            p1.join()
            p2.join()
            p3.join()

            d0 = q0.get()
            d1 = q1.get()
            d2 = q2.get()
            d3 = q3.get()
            c0 = q0.get()
            c1 = q1.get()
            c2 = q2.get()
            c3 = q3.get()

            d = [d0, d1, d2, d3]
            c = [c0, c1, c2, c3]

            m = max(d)
            i = d.index(m)
            n = c[i]

            l.append(n)
            out.write("[" + str(n[0]) + ", " + str(n[1]) + ", " + str(n[2]) + "]\n")
            print "\nnew colour added: " + str(l)

        out.close()
        print "Done"


gen_colours()

有什么建议吗?你知道吗

编辑:

一个明显的改进是我每次都在计算找到的rgb颜色的Lab值。我添加了一个列表来存储这些的Lab值,这样就不需要每次循环都这样做了。这减少了大约1/4的时间。然而,这并不是我想要的Python性能改进。你知道吗


Tags: getreturnifrgbsqrth2h1multiprocessing
2条回答

你做的工作太多了。你知道吗

当大多数监视器/色域/环境光/眼睛组合提供的辨别能力远远低于CIE计算产生的辨别能力时,您似乎正在24位RGB颜色空间中工作。你知道吗

假设你这样做是为了给真实的眼睛提供真实世界的颜色,你还必须考虑到色盲的无数形式,这将使你减少到不到12位有用的颜色空间。即使我们只是谈论亮度,当亮度接近设备色域的较低三分之一时,明显的差异变得越来越稀疏。你知道吗

你所面临的问题是算法;也就是说,当添加的细节不相关时,你太努力了,无法得到详细的结果。在#000和#fff之间,只有4096种可能的颜色,红-绿轴可以立即拒绝。你知道吗

我敢肯定,如果已经选择了R:100G:100B:100的颜色,那么R:100G:100B:101的颜色就不是“最具特色”的解决方案。你知道吗

在给定的范围内,哪一种颜色是可以忽略的。你知道吗

相关问题 更多 >