需要提高图像创建速度

时间:2017-06-01 22:10:03

标签: python image numpy colors

我尝试使用各种可能的颜色创建图像。它将以种子像素开始,然后在其周围放置随机生成的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种颜色,并且随着速度的增加而逐渐减慢。我无法弄清楚如何花费更少的时间,而且我知道必须有一种方法可以做到这一点并不需要数月。我是新手编码并且正在自学,所以请原谅任何我完全忽视的明显修复。

1 个答案:

答案 0 :(得分:0)

好的,我花了一些时间看这个并且我做了一些改变以加快速度。我非常喜欢你在这个程序中实现的想法,输出非常可爱。我可能会从一开始就做一些不同的事情,但事实上,我已经将它留在了你提出的结构中,并进行了一些调整。这绝不代表代码可能是最快或最有效的,但它足以满足我的加速。 Note - 我可能会使用一些错误的打印语句来了解代码中发生了什么。希望它有所帮助。

  1. 我清理了代码以删除任何未使用的内容并更改循环访问某些对象的方式。这些都是风格变化,而不是其他任何东西。

  2. 我将颜色立方体从numpy数组更改为元组,因为np数组不是必需的。我认为立方体现在生成得更快,但我还没有做任何测试来证实这一点。

  3. 重要的是要明白,鉴于您希望处理颜色的方式,此算法将随着时间的推移而减慢,因为周长数量为#34;候选人成长。当我第一次运行代码时,由于坐标没有被正确删除,我的周边列表的大小正在大幅增长。我无法追踪它发生的原因,所以我在程序中添加了额外的检查,以避免覆盖已写入的任何像素。如果发现一个点不应该是周边列表的成员,我还添加了一些冗余点删除。这对我的系统起了很大的作用,虽然这个bug的来源仍然无法实现。

  4. 为了进一步解决与周长大小成比例增长的处理时间问题,我在genPoint中引入了一个阈值。这允许函数在足够接近时退出&#34;到一个好位置。这样做有很高的质量,因此如果想要速度,可以设置更高的值,如果想要更高质量的图像,可以设置更低的值。这是一个魔鬼的讨价还价,但替代方案是一个永远不会完成的程序。当我第一次运行脚本时,我的计算机花了大约14秒完成迭代14000-14500。由于目前正在进行迭代2,330,000,而且每500次迭代需要2-3秒。

  5. 我摆脱了未填充的字典,而是直接从函数中引用了图像。不是我更喜欢这样做,但它简化了代码并摆脱了大内存块。

  6. 另一种更明显的加速方法是多线程迭代 genPoint()函数,但我不愿意投入时间要做到这一部分,因为它需要对代码进行大量的改造。为了使其工作,你必须实现许多线程锁,但它会使它更快。

  7. -

    from PIL import Image
    import sys
    import random
    import itertools
    import datetime as dt
    
    
    #sys.setcheckinterval(10000)
    
    def surroundAvg(points):
        surrounding = {}
        for inc in points:
            neighbors = filledNeighbors(inc[0],inc[1])
            nearcount = len(neighbors)
            pixred = 0
            pixgreen = 0
            pixblue = 0
            for n in neighbors:
                (temp_red,temp_green,temp_blue) = pixels[n[0],n[1]]
                pixred += temp_red
                pixgreen += temp_green
                pixblue += temp_blue
            pixred = pixred / nearcount
            pixgreen = pixgreen / nearcount
            pixblue = pixblue / nearcount
            surrounding[(inc[0],inc[1])] = (pixred,pixgreen,pixblue)
        return surrounding
    
    def genPoint(perim,averages,red,green,blue):
        test = 0
        least_diff = 9999
        threshold = 35
        for point in perim:
            i = point[0]
            j = point[1]
            if pixels[i,j] == (0,0,0):
                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
                    if least_diff < threshold:
                        return newx,newy,perim
            else:
                perim.pop(perim.index(point))
        return newx,newy,perim
    
    def cubegen():  #create the cube of colors with each color having its own number
        cube = []
        num = 0
        for red in xrange(0,256):
            for green in xrange(0,256):
                for blue in xrange(0,256):
                    cube.append((red,green,blue))
                    num += 1
        return tuple(cube)
    
    def getNeighbors(x,y):
        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 pixels[i,j] != (0,0,0) or j < 0 or i < 0:
                toremove.append((i,j))
        map(neighbors.remove,toremove)
        return neighbors
    
    def filledNeighbors(x,y):
        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 pixels[i,j] == (0,0,0) 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
    
    print("Making list")
    colorList = range(16777216)
    random.shuffle(colorList)
    print("Color list shuffled successfully")
    
    print("Making cube")
    colorCube = cubegen()
    print("Color cube created successfully")
    
    startx = 2048
    starty = 2048
    color = colorList[0]
    
    (red,green,blue) = colorCube[color]
    #start with a random color
    pixels[startx,starty] = (red,green,blue)
    
    #get it's neighboring pixels
    perim_empty = getNeighbors(startx,starty)
    
    #calc avg values (original pixel)
    avg = surroundAvg(perim_empty)
    print("First point placed successfully.")
    appendPerim = perim_empty.append
    removePerim = perim_empty.remove
    updateAvg = avg.update
    
    start = dt.datetime.now()
    for iteration in xrange(1,16777216):
        temp = {}
        color = colorList[iteration]
        (red,green,blue) = colorCube[color]
        i,j,perim_empty = genPoint(perim_empty,avg,red,green,blue)
        pixels[i,j] = (red,green,blue)
        new_neighbors = getNeighbors(i,j)
        map(appendPerim,new_neighbors)
        temp = surroundAvg(new_neighbors)
        updateAvg(temp)
        removePerim((i,j))
        for p in perim_empty:
            if p[0] == i and p[1] == j:
                perim_empty.remove(p)
    
        if iteration % 1000 == 0:
            end = dt.datetime.now()
            print("Iteration %d complete: %f" %(iteration,(end-start).total_seconds()))
            print("Perimeter size: %d"%len(perim_empty))
            print("Averages size: %d"%sys.getsizeof(avg))
            start = dt.datetime.now()
            img.save("%06d.png" % (iteration/1000))
    
    img.save("Perimeter Averaging Final.bmp")
    img.show()
    

    编辑:忘记包含我当前的图片(仍在增长): cropped output image