2014-10-19 82 views
1

我目前正在使用PhotoImage和tkinter繪製Mandelbrot像素。我基本上直接使用算法而不做任何修改。有沒有使計算更快的方法?也許可以快速填充大面積的顏色,或預先確定常量?代碼如何渲染Mandelbrot設置更快?

部分:

ITERATIONS = 50 
WIDTH, HEIGHT = 600, 600 
CENTER = (-.5, 0) 
DIAMETER = 2.5 

def mandel(c): 
    z = 0 
    for i in range(ITERATIONS): 
     z = z**2 + c 
     if abs(z) > 2: 
      return i  
    return ITERATIONS 

root = Tk() 
canvas = Canvas(root, width=WIDTH,height=HEIGHT) 
canvas.pack() 
img = PhotoImage(width=WIDTH, height=HEIGHT) 
canvas.create_image((WIDTH/2, HEIGHT/2), image=img, state="normal") 


real = CENTER[0] - 0.5 * DIAMETER 
imag = CENTER[1] - 0.5 * DIAMETER 

def color(i): 
    colors = ("#0000AA", "#88DDFF", "#FF8800", "#000000") 
    if i == ITERATIONS: 
     return colors[-1] 
    else: 
     choice = (i//2) % len(colors) 
    return colors[choice] 

for x in range(WIDTH): 
    for y in range(HEIGHT): 
     i = mandel(complex(real, imag)) 

     img.put(color(i), (x, HEIGHT-y)) 

     imag += DIAMETER/HEIGHT 
    imag = CENTER[1] - 0.5 * DIAMETER 
    real += DIAMETER/WIDTH 

mainloop() 
+0

勞駕這裏補充,並在各自的提案都尊重StackOverflow的答案作者,說明你的初始**代碼執行時間[微秒] **(+相應的解決方案的,其中提出的) ,爲快速方法必須擊敗的基準和基準,以及您期望的加速度閾值是多少 - 您希望該過程獲得多快?感謝您的kinde重新考慮。 – user3666197 2014-10-19 08:26:07

回答

4

一次設置一個像素可能是減速的主要來源。不要爲每個像素調用put,而應該計算整行像素或整個像素矩陣,然後在循環結束時調用一次。

你可以在這裏找到一個例子,在其他地方:http://tkinter.unpythonic.net/wiki/PhotoImage#Fill_Many_Pixels_at_Once

+0

迄今爲止最好的結果,除了用numpy重寫 – qwr 2014-10-19 21:16:16

0

純Python是不是快數字代碼。加快速度的最簡單方法是使用PyPy。如果速度不夠快,請使用numpy向量化您的算法。如果仍然不夠快,可以使用Cython,或者考慮用C語言重寫它。

1

爲了適度提高速度(但不足以抵消編譯語言和解釋語言之間的差異),您可以預先計算一些的價值。

現在,您計算每個內循環一次DIAMETER/HEIGHT,每個外循環一次計算CENTER[1] - 0.5 * DIAMETER以及DIAMETER/WIDTH。事先做好。

len(colors)也不會改變,可以用一個常量代替。事實上,我可能會寫功能

def color(i): 
    if i == ITERATIONS: 
     return "#000000" 
    else: 
     return ("#0000AA", "#88DDFF", "#FF8800", "#000000")[(i//2) % 4] 
     # are you sure you don't want ("#0000AA", "#88DDFF", "#FF8800")[(i//2) % 3] ? 

此外,x**2x*x慢(因爲x**y運算符不快捷方式的y==2瑣碎的情況下),這樣你就可以速度計算了位。

1

大部分時間都花在mandel()的內部循環中。 z*z而不是z**2有輕微影響。我可以看到沒有其他的東西可以加速。去除其他循環中的常量效果不大,但我傾向於這樣做。選擇ITERATIONS以便ITERATIONS//2 % len(colors) == len(colors)-1(如46 //2 % 4 == 3)允許簡化代碼。圍繞x軸開發對稱將時間縮短一半。從0開始成像可以避免從+/- DIAMETER/2減去300次的舍入誤差,並在圖像中產生乾淨的中心線。

from tkinter import * 

ITERATIONS = 46 
WIDTH, HEIGHT = 601, 601 # odd for centering and exploiting symmetry 
DIAMETER = 2.5 

start = (-.5 - DIAMETER/2, 0) # Start y on centerline 
d_over_h = DIAMETER/HEIGHT 
d_over_w = DIAMETER/WIDTH 

def mandel(c): 
    z = 0 
    for i in range(ITERATIONS): 
     z = z*z + c 
     if abs(z) > 2: 
      return i  
    return ITERATIONS 

root = Tk() 
canvas = Canvas(root, width=WIDTH,height=HEIGHT) 
canvas.pack() 
img = PhotoImage(width=WIDTH, height=HEIGHT) 
canvas.create_image(((WIDTH+1)//2, (HEIGHT+1)//2), image=img, state="normal") 


real, imag = start 

colors = ("#0000AA", "#88DDFF", "#FF8800", "#000000") 
ncolors = len(colors) 
yrange = range(HEIGHT//2, -1, -1) # up from centerline 
ymax = HEIGHT - 1 

for x in range(WIDTH): 
    for y in yrange: 
     i = mandel(complex(real, imag)) 
     color = colors[i//2 % ncolors] 
     img.put(color, (x, y)) 
     img.put(color, (x, ymax - y)) 
     imag += d_over_h 
    imag = start[1] 
    real += d_over_w 

mainloop() 
1

這裏是我的代碼,它繪製一個640×480曼德爾布羅在8-9秒。

它每像素多達256次迭代,使用顏色映射列表,'只'放置一次到PhotoImage並且不依賴於symetry,因此它可以顯示該集合的任何縮放區域。

很遺憾,Tkinter不允許訪問PhotoImage的柵格信息作爲緩衝區,並且需要笨拙的字符串。

from tkinter import Tk, Canvas, PhotoImage,NW,mainloop 
from time import clock 

def mandel(kx,ky): 
    """ calculates the pixel color of the point of mandelbrot plane 
     passed in the arguments """ 

    global clr 
    maxIt = 256 
    c = complex(kx, ky) 
    z = complex(0.0, 0.0) 
    for i in range(maxIt): 
     z = z * z + c 
     if abs(z) >= 2.0: 
     return (255-clr[i],0,0) 
    return(0,0,0) 

def prepare_mdb(xa,xb,ya,yb): 
    """ pre-calculates coordinates of the mandelbrot plane required for each 
     pixel in the screen""" 

    global x,y,xm,ym 
    xm.clear 
    ym.clear 
    xm=[xa + (xb - xa) * kx /x for kx in range(x)] 
    ym=[ya + (yb - ya) * ky /y for ky in range(y)] 


x=640 
y=480 
#corners of the mandelbrot plan to display 
xa = -2.0; xb = 1.0 
ya = -1.5; yb = 1.5 
#precalculated color table 
clr=[ int(255*((i/255)**12)) for i in range(255,-1,-1)] 
xm=[] 
ym=[] 
prepare_mdb(xa,xb,ya,yb) 

#Tk 
window = Tk() 
canvas = Canvas(window, width = x, height = y, bg = "#000000") 
t1=clock() 
img = PhotoImage(width = x, height = y) 
canvas.create_image((0, 0), image = img, state = "normal", anchor = NW) 
pixels=" ".join(("{"+" ".join(('#%02x%02x%02x' % mandel(i,j) for i in xm))+"}" for j in ym)) 
img.put(pixels) 
canvas.pack() 
print(clock()-t1) 
mainloop() 

enter image description here