【问题标题】:Incorrect results with genetic algorithm image evolution遗传算法图像进化的结果不正确
【发布时间】:2014-09-27 20:01:03
【问题描述】:

我正在尝试实现最初由Roger Alsing 创建的程序。我已经对其他人实施的内容进行了相当多的研究。我决定用 python 编写我的程序,并使用基本的三角形作为形状。当我运行程序时,经过几代后它并没有显示出改进(三角形往往会消失)。我假设我的 mutate 函数有问题。谁能告诉我为什么它产生的结果不尽如人意?

我的代码:

import random
import copy
from PIL import Image, ImageDraw

optimal = Image.open("mona_lisa.png")
optimal = optimal.convert("RGBA")

size = width, height = optimal.size

num_shapes = 128

generations = 50000

def random_genome():
    elements = []

    for i in range(num_shapes):
        x = (random.randint(0, width), random.randint(0, height))
        y = (random.randint(0, width), random.randint(0, height))
        z = (random.randint(0, width), random.randint(0, height))
        r = random.randint(0, 255)
        g = random.randint(0, 255)
        b = random.randint(0, 255)
        alpha = random.randint(10, 255)

        elements.append([x, y, z, r, g, b, alpha])

    return elements

def render_daughter(dna):
    image = Image.new("RGBA", (width, height), "white")
    draw = ImageDraw.Draw(image)

    for item in dna:
        x = item[0]
        y = item[1]
        z = item[2]
        r = item[3]
        g = item[4]
        b = item[5]
        alpha = item[6]

        color = (r, g, b, alpha)

        draw.polygon([x, y, z], fill = color)

    return image

def mutate(dna):
    dna_copy = copy.deepcopy(dna)

    shape_index = random.randint(0, len(dna) - 1)
    roulette = random.random() * 2

    if roulette < 1:

        if roulette < 0.25:
            dna_copy[shape_index][3] = int(random.triangular(255, dna_copy[shape_index][3]))

        elif roulette < 0.5:
            dna_copy[shape_index][4] = int(random.triangular(255, dna_copy[shape_index][4]))

        elif roulette < 0.75:
            dna_copy[shape_index][5] = int(random.triangular(255, dna_copy[shape_index][5]))

        elif roulette < 1.0:
            dna_copy[shape_index][6] = int(0.00390625 * random.triangular(255, dna_copy[shape_index][6] * 255))

    else:

        if roulette < 1.25:
            dna_copy[shape_index][0] = (int(random.triangular(width, dna_copy[shape_index][0][0])), int(random.triangular(height, dna_copy[shape_index][0][1])))

        elif roulette < 1.5:
            dna_copy[shape_index][2] = (int(random.triangular(width, dna_copy[shape_index][3][0])), int(random.triangular(height, dna_copy[shape_index][4][1])))

        elif roulette < 1.75:
            dna_copy[shape_index][3] = (int(random.triangular(width, dna_copy[shape_index][4][0])), int(random.triangular(height, dna_copy[shape_index][5][1])))

    return dna_copy

def fitness(original, new):
    fitness = 0

    for x in range(0, width):
        for y in range(0, height):
            r1, g1, b1, a1 = original.getpixel((x, y))
            r2, g2, b2, a2 = new.getpixel((x, y))

            deltaRed = r1 - r2
            deltaGreen = g1 - g2
            deltaBlue = b1 - b2
            deltaAlpha = a1 - a2

            pixelFitness = deltaRed + deltaGreen + deltaBlue + deltaAlpha

            fitness += pixelFitness

    return fitness

def generate():
    mother = random_genome()
    best_genome = mother
    best_fitness = fitness(optimal, render_daughter(best_genome))


    for i in range(generations):
        daughter = copy.deepcopy(best_genome)
        daughter = mutate(daughter)

        daughter_fitness = fitness(optimal, render_daughter(daughter))

        if daughter_fitness < best_fitness:
            best_genome = daughter
            best_fitness = daughter_fitness

        if i % 50 == 0:
            print i

        if i % 1000 == 0:
            render_daughter(best_genome).save("iterations/output_" + str(i) + ".png")

if __name__ == "__main__":
    generate()

我正在使用的开始图片:

1000代后的输出图像:

5000 代后的输出图像:

【问题讨论】:

    标签: python genetic-algorithm


    【解决方案1】:

    您正在检查新适应度是否小于当前适应度:

    if daughter_fitness < best_fitness:
    

    但是,您计算的适应度可能为负数:

    deltaRed = r1 - r2
    deltaGreen = g1 - g2
    deltaBlue = b1 - b2
    deltaAlpha = a1 - a2
    
    pixelFitness = deltaRed + deltaGreen + deltaBlue + deltaAlpha
    
    fitness += pixelFitness
    

    各种delta*变量可以是负数也可以是正数;您的测试将支持负增量,增加“最佳”图像的白度(r2g2 等的值越高,适应度越低,图像越白,直到它们都在 255、255、 255. 我不知道增加 alpha 是增加还是减少透明度)。

    因此,您应该取差值的绝对值:

    deltaRed = abs(r1 - r2)
    deltaGreen = abs(g1 - g2)
    deltaBlue = abs(b1 - b2)
    deltaAlpha = abs(a1 - a2)
    

    您还可以考虑平方和,或平方和的平方根(基本上,将其转换为最小二乘拟合例程):

    deltaRed = r1 - r2
    deltaGreen = g1 - g2
    deltaBlue = b1 - b2
    deltaAlpha = a1 - a2
    
    pixelFitness = math.sqrt(deltaRed**2 + deltaGreen**2 + deltaBlue**2 + deltaAlpha**2)
    
    fitness += pixelFitness
    

    最后,我注意到您的程序不适合我。它位于 mutate() 函数的后半部分,您可以在其中为 x、y 或 z 分配新值,但使用大于 2 的索引。random_genome() 表明您尝试访问颜色值,它们是整数,甚至尝试索引这些。

    这会导致异常,所以我什至不知道如何让这个程序运行。它要么一开始就没有运行过,要么你没有正确地复制粘贴。我已将其更改为

    if roulette < 1.25:
        dna_copy[shape_index][0] = (int(random.triangular(
            width, dna_copy[shape_index][0][0])), int(
                random.triangular(height, dna_copy[shape_index][0][1])))
    elif roulette < 1.5:
        dna_copy[shape_index][1] = (int(random.triangular(
            width, dna_copy[shape_index][1][0])), int(
                random.triangular(height, dna_copy[shape_index][1][1])))
    elif roulette < 1.75:
        dna_copy[shape_index][2] = (int(random.triangular(
            width, dna_copy[shape_index][2][0])), int(
                random.triangular(height, dna_copy[shape_index][2][1])))
    

    这似乎可以满足您的需求。

    【讨论】:

    • 感谢您帮助我,先生。这清楚了很多事情。虽然,我注意到 PIL 不能很好地处理透明度,因为没有一个三角形看起来是半透明的。你知道这是为什么吗?
    • 蒂姆,我不知道透明度。我的 png 确实显示了透明度,但话又说回来,我使用的是 Pillow,而不是 PIL(相同的界面,更新的代码)。
    • 我在看那个。我一定要检查一下。谢谢先生。
    • 你运行了那个脚本吗?即使在此修复后也无法获得任何好的结果
    • @AntonShkurenko 我可能有,但那已经是 3 年前多了。我当然不能告诉你我当时是否取得了好成绩。但是,“不能得到任何好的结果”并不能很清楚地说明您面临的问题。我建议您使用固定脚本创建一个新问题,链接到该问题,指出即使进行了修复,您也会得到不好的结果,然后显示您实际得到的结果(以及您的期望)。
    猜你喜欢
    • 2014-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-12-21
    • 2015-06-04
    • 2017-06-10
    • 2015-02-18
    • 2013-07-02
    相关资源
    最近更新 更多