Incorrect results with genetic algorithm image evolution

拟墨画扇 提交于 2019-12-10 17:26:03

问题


I'm attempting to implement a program originally created by Roger Alsing. I've done quite a bit of research on what other people have implemented. I decided to write my program in python, and use basic triangles as the shapes. When I run the program, it does not show improvement after more generations (The triangles tend to just disappear). I'm assuming something is wrong with my mutate function. Can anyone tell me why its producing less than satisfactory results?

My code:

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()

The beginning image I am using:

The output image after 1,000 generations:

Output image after 5,000 generations:


回答1:


You're checking wheter the new fitness is smaller than the current fitness:

if daughter_fitness < best_fitness:

The fitness you calculate, however, can be negative:

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

pixelFitness = deltaRed + deltaGreen + deltaBlue + deltaAlpha

fitness += pixelFitness

The various delta* variables can be negative or positive; your test will favour negative deltas, increasing the whiteness of the "best" image (the higher values of r2, g2 etc, the lower the fitness, and the whiter the image, until they are all at 255, 255, 255. I don't know if increasing alpha increases or decreases the transparency).

Thus, you should take the absolute value of the differences:

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

You could also consider the sum of the square, or square root of the sum of squares (which, basically, turns it into a least-squares fitting routine):

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

Finally, I noticed your program doesn't work for me. It's in the second half of your mutate() function, where you assign new values to x, y or z, but use indices above 2. random_genome() shows that you try to access colour values instead, which are integers, and even attempt to index those.

This leads to exceptions, so I don't even know how you could get this program running. It either never ran in the first place, or you didn't properly copy-paste. I've changed that to

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])))

which seems to do what you want.



来源:https://stackoverflow.com/questions/25134050/incorrect-results-with-genetic-algorithm-image-evolution

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!