【发布时间】:2017-11-03 05:06:21
【问题描述】:
我正在尝试创建具有所有可能颜色的图像。它将从一个种子像素开始,然后在其周围放置随机生成的 RGB 像素。未来的放置将基于其周围像素的平均值最接近要放置的新颜色的任何开放点。
from PIL import Image
import numpy as np
from random import randint
import sys
import random
import itertools
sys.setcheckinterval(10000)
def moddistance3(x1,y1,z1,x2,y2,z2): #get relative distance between two 3D points
x = abs(x1 - x2)
y = abs(y1 - y2)
z = abs(z1 - z2)
return (x + y + z)
def genColor(unused): #generate random color (not used anymore)
test = 0
while test == 0:
red = randint(0,255)
green = randint(0,255)
blue = randint(0,255)
if unused[red,green,blue] == 1:
test = 1
return (red,green,blue)
def surroundAvg(points,unfilled):
surrounding = {}
count = len(points)
for inc in xrange(count):
neighbors = filledNeighbors(points[inc][0],points[inc][1],unfilled)
nearcount = len(neighbors)
pixred = 0
pixgreen = 0
pixblue = 0
for num in xrange(nearcount):
(temp_red,temp_green,temp_blue) = pixels[neighbors[num][0],neighbors[num][1]]
pixred = pixred + temp_red
pixgreen = pixgreen + temp_green
pixblue = pixblue + temp_blue
pixred = pixred / nearcount
pixgreen = pixgreen / nearcount
pixblue = pixblue / nearcount
surrounding[(points[inc][0],points[inc][1])] = (pixred,pixgreen,pixblue)
return surrounding
def genPoint(perim,unfilled,averages,red,green,blue):
num_test = len(perim)
test = 0
least_diff = 9999
nearby = []
for point in xrange(num_test):
i = perim[point][0]
j = perim[point][1]
pixred = averages[(i,j)][0]
pixgreen = averages[(i,j)][1]
pixblue = averages[(i,j)][2]
diff = abs(red - pixred) + abs(green - pixgreen) + abs(blue - pixblue)
if diff < least_diff or test == 0:
least_diff = diff
newx = i
newy = j
test = 1
return newx,newy
def cubegen(): #create the cube of colors with each color having its own number
cube = np.zeros(16777216,dtype=np.object)
num = 0
for red in xrange(0,256):
for green in xrange(0,256):
for blue in xrange(0,256):
cube[num] = [red,green,blue]
num += 1
return cube
def getNeighbors(x,y,unfilled):
Prod = itertools.product
toremove = []
neighbors = list(Prod(range(x-1,x+2),range(y-1,y+2)))
for num in xrange(len(neighbors)):
i,j = neighbors[num]
if j > 4095 or i > 4095 or unfilled[(i,j)] == 0 or j < 0 or i < 0:
toremove.append((i,j))
map(neighbors.remove,toremove)
return neighbors
def filledNeighbors(x,y,unfilled):
Prod = itertools.product
toremove = []
neighbors = list(Prod(range(x-1,x+2),range(y-1,y+2)))
#neighbors = filter(lambda i,j: j < 4096 and i < 4096 and unfilled[i,j] == 0 and j > -1 and i > -1,allneighbors)
for num in xrange(len(neighbors)):
i,j = neighbors[num]
if j > 4095 or i > 4095 or unfilled[(i,j)] == 1 or j < 0 or i < 0:
toremove.append((i,j))
map(neighbors.remove,toremove)
return neighbors
img = Image.new('RGB', (4096,4096)) # create a new black image
pixels = img.load() # create the pixel map
colorList = range(16777216)
colorCube = cubegen()
print("Color cube created successfully")
unfilled = {}
for x in xrange(4096):
for y in xrange(4096):
unfilled[(x,y)] = 1
startx = 2048
starty = 2048
random.shuffle(colorList)
print("Color list shuffled successfully")
color = colorList[0]
(red,green,blue) = colorCube[color]
pixels[startx,starty] = (red,green,blue)
unfilled[(startx,starty)] = 0
perim_empty = getNeighbors(startx,starty,unfilled)
edge = []
#edge.append((startx,starty))
avg = surroundAvg(perim_empty,unfilled)
print("First point placed successfully.")
#appendEdge = edge.append
#removeEdge = edge.remove
appendPerim = perim_empty.append
removePerim = perim_empty.remove
updateAvg = avg.update
for iteration in xrange(1,16777216):
temp = {}
color = colorList[iteration]
(red,green,blue) = colorCube[color]
(i,j) = genPoint(perim_empty,unfilled,avg,red,green,blue)
unfilled[(i,j)] = 0
pixels[i,j] = (red,green,blue)
new_neighbors = getNeighbors(i,j,unfilled)
map(appendPerim,new_neighbors)
temp = surroundAvg(new_neighbors,unfilled)
updateAvg(temp)
removePerim((i,j))
#appendEdge((i,j))
#if iteration % 20 == 0:
# toremove = []
# appendToRemove = toremove.append
# for num in xrange(len(edge)):
# nearby = getNeighbors(edge[num][0],edge[num][1],unfilled)
# if len(nearby) == 0:
# appendToRemove(edge[num])
#for num in xrange(len(toremove)):
# edge.remove(toremove[num])
# map(removeEdge,toremove)
if iteration % 500 == 0:
print("Iteration %d complete" %iteration)
if iteration == 100000 or iteration == 500000 or iteration ==1000000 or iteration == 5000000 or iteration == 10000000 or iteration == 15000000:
img.save("Perimeter Averaging -- %d iterations.bmp" %iteration)
img.save("Perimeter Averaging Final.bmp")
img.show()
问题是,当我尝试运行它时,甚至需要数天才能通过 1,000,000 种颜色,并且运行速度会大大降低。我不知道如何让它花费更少的时间,而且我知道必须有一种方法可以做到这一点,而不需要几个月的时间。我是编码新手并且正在自学,所以请原谅我完全忽略的任何明显的修复。
【问题讨论】:
-
在没有专门查看您的代码的情况下,您是否考虑过
cython-izing 或使用像numba这样的 JIT 编译器? -
你是对的,这可以运行得更快。我猜想将庞大的
字典从一个函数扔到另一个函数可能是一个相当大的瓶颈。该程序在进入迭代部分之前会消耗大量内存。肯定有一些领域你可以更有效地处理。如果我有时间的话,我今晚会去列个清单。 -
无论何时尝试加速您的代码,最好对其进行概要分析以确定其大部分时间都花在哪里......所以您知道在这里花费大部分时间来优化它。见How can you profile a python script?也就是说,答案通常是完全使用不同的算法并避免瓶颈,不管它是什么。
-
您需要学习您的数据结构...您正在使用列表或 numpy 数组,但它们的优势却不尽如人意。我认为这个问题属于Code Review,而不是这里。而且您在那里比在这里更有可能获得切实可行的帮助。
-
我尝试使用 cProfile 对其进行分析,大部分时间似乎都被 genPoint 消耗了,特别是因为它被频繁调用。问题是我找不到在不增加花费时间的情况下更改它的方法。您会推荐哪些数据结构来更好地利用它们的优势?