使用遗传算法进行图像演化的结果不正确

时间:2015-09-04 21:23:39

标签: python-3.x genetic-algorithm genetic-programming

我遵循与此链接相同的想法(Incorrect results with genetic algorithm image evolution)但是,我在获取任何正确结果方面遇到了一些麻烦。我的代码与此处的代码明显不同。我有一个初始的monalisa图像,但即使有5000/10000迭代我得到这样的图像。我正在采用基于男/女和颜色的不同边界框。

我在这里做错了什么?

# draw about 50 polygons with varying transparencies to recreate an image
from PIL import Image, ImageDraw, ImageChops
from random import random, randint
import numpy as np

def clamp(minimum, x, maximum):
    return max(minimum, min(x, maximum))

def pil2array(img):
    return np.array(img.getdata(),
                    np.uint8).reshape(img.size[1], img.size[0], 3)

def array2pil(arr, size):
    mode = 'RGBA'
    arr = arr.reshape(arr.shape[0]*arr.shape[1], arr.shape[2])
    if len(arr[0]) == 3:
        arr = np.c_[arr, 255*np.ones((len(arr),1), np.uint8)]
    return Image.frombuffer(mode, size, arr.tostring(), 'raw', mode, 0, 1)

class Point:
    def __init__(self, x, y):
        self.__x = x
        self.__y = y

    @property
    def x(self):
        return self.__x

    @property
    def y(self):
        return self.__y

class Individual:
    """
    Biggest_bounding_box is a list of [min_x, max_x, min_y, max_y]
    """
    def __init__(self, bounding_box, color, biggest_bounding_box):
        self.__bounding_box = bounding_box
        self.__color = color
        self.__biggest_bounding_box = biggest_bounding_box

    @property
    def bounding_box(self):
        return self.__bounding_box

    @property
    def color(self):
        return self.__color

    def mutate(self):
        mutation_type = randint(0, 3)
        if mutation_type == 0:
            self.__bounding_box[0] = randint(self.__biggest_bounding_box[0], self.__biggest_bounding_box[1])
            self.__bounding_box[2] = randint(self.__biggest_bounding_box[0], self.__biggest_bounding_box[1])

        if mutation_type == 1:
            self.__bounding_box[1] = randint(self.__biggest_bounding_box[0], self.__biggest_bounding_box[1])
            self.__bounding_box[3] = randint(self.__biggest_bounding_box[0], self.__biggest_bounding_box[1])

        if mutation_type == 2:
            self.__color = (randint(0, 255), randint(0, 255), randint(0, 255), randint(0, 255))

    def draw(self, draw):
        draw.ellipse(self.__bounding_box, fill=self.__color)

    def __str__(self):
        output_str = str(self.__bounding_box) + " --> color: " + str(self.__color)
        return output_str

    __repr__ = __str__

class Evolve:
    def __init__(self, img):
        self.__target = Image.open(img)
        self.__width = self.__target.width
        self.__height = self.__target.width
        print(self.__target.size)
        self.__biggest_bounding_box = [0, self.__target.width, 0, self.__target.height]

    def __get_bounding_box(self, center, radius):
        x_top = clamp(0, center.x - radius, self.__width)
        y_top = clamp(0, center.y - radius, self.__height)

        x_bottom = clamp(0, center.x + radius, self.__width)
        y_bottom = clamp(0, center.y + radius, self.__height)

        bb = [x_top, y_top, x_bottom, y_bottom]
        return bb

    def individual(self, min_radius, max_radius, min_x, max_x, min_y, max_y):
        center = Point(randint(min_x, max_x), randint(min_y, max_y))
        radius = randint(min_radius, max_radius)
        bounding_box = self.__get_bounding_box(center, radius)
        color = (randint(0, 255), randint(0, 255), randint(0, 255), randint(0, 255))
        return Individual(bounding_box, color, [min_x, max_x, min_y, max_y])

    def population(self, individual_count, min_radius, max_radius):
        min_x = 0
        max_x = self.__target.width
        min_y = 0
        max_y = self.__target.height
        return [self.individual(min_radius, max_radius, min_x, max_x, min_y, max_y) for i in range(0, individual_count)]

    def fitness(self, individual):
        nimg = Image.new(self.__target.mode, (self.__width, self.__height), color=(255, 255, 255, 255))
        draw = ImageDraw.Draw(nimg)
        draw.ellipse(individual.bounding_box, fill=individual.color)

        diff = ImageChops.difference(self.__target, nimg)
        arr = np.array(diff)
        # arr = pil2array(diff)
        return np.sum(np.absolute(arr))

    def grade(self, pop):
        """
        Find average fitness of the population
        :return: returns the average fitness
        """
        summed = np.sum([self.fitness(individual) for individual in pop])
        return summed / (len(pop) * 1.0)

    def evolve_population(self, pop, retain=0.2, random_select=0.5, mutate=0.1):
        graded = [(self.fitness(individual), individual) for individual in pop]
        graded = [x[1] for x in sorted(graded, key=lambda tup: tup[0])]
        retain_length = int(len(graded) * retain)
        parents = graded[:retain_length]

        # randomly add other individuals to promote genetic diversity
        for individual in graded[retain_length:]:
            if random_select > random():
                parents.append(individual)

        # mutate some individuals
        for individual in parents:
            if mutate > random():
                individual.mutate()

        # Crossover the parents to create children
        parents_length = len(parents)
        desired_length = len(pop) - parents_length
        children = []

        while len(children) < desired_length:
            # randomly decide whether we want to take the x,y from male &
            # color from female or vice-versa
            male_idx = randint(0, parents_length-1)
            female_idx = randint(0, parents_length-1)

            male = parents[male_idx]
            female = parents[female_idx]

            if male != female:
                which_one = [male, female]

                top_x = which_one[randint(0, 1)].bounding_box[0]
                top_y = which_one[randint(0, 1)].bounding_box[1]

                bottom_x = which_one[randint(0, 1)].bounding_box[2]
                bottom_y = which_one[randint(0, 1)].bounding_box[3]

                color_r = which_one[randint(0, 1)].color[0]
                color_g = which_one[randint(0, 1)].color[1]
                color_b = which_one[randint(0, 1)].color[2]
                color_a = which_one[randint(0, 1)].color[3]

                child = Individual([top_x, top_y, bottom_x, bottom_y], (color_r, color_g, color_b, color_a), self.__biggest_bounding_box)
                children.append(child)

        parents.extend(children)
        return parents

    def render_population(self, pop):
        nimg = Image.new(self.__target.mode, (self.__width, self.__height))
        drawobj = ImageDraw.Draw(nimg)
        for individual in pop:
            individual.draw(drawobj)

        return nimg

def main():
    target = 'monalisa.png'
    ev = Evolve(target)
    individual_count = 100
    p = ev.population(individual_count, min_radius=20, max_radius=40)
    fitness_history = [ev.grade(p)]

    for i in range(25000):
        p = ev.evolve_population(p)
        grade = ev.grade(p)
        print(grade)
        fitness_history.append(grade)
        nimg = ev.render_population(p)

        if i == 5000 or i == 10000 or i == 15000 or i == 20000 or i == 25000:
            nimg.save('iterations/%s.png' % i)

if __name__ == "__main__":
    main()

原始图片是下面的第一张图片。内嵌图像对我不起作用。

  

http://i.stack.imgur.com/m38tc.png http://i.stack.imgur.com/1RGSr.png   http://i.stack.imgur.com/ewvTM.png

0 个答案:

没有答案