Memory leak problem (while using tkinter)

André andre.roberge at gmail.com
Wed Dec 31 05:21:06 CET 2008


I have written a small program (my first Tkinter-based app) to play
around the idea mentioned on
http://rogeralsing.com/2008/12/07/genetic-programming-evolution-of-mona-lisa/
and, in doing so, have encountered a memory leak problem.   I have
seen mentions on the web of using the delete() method of canvas to
prevent such problems - which I have tried to do with limited
success.  Below is the code I wrote; to run it, you will need a small
image file
(I used the one found on http://alteredqualia.com/visualization/evolve/)
that is saved under "mona_lisa.png".

Any help would be greatly appreciated.

André
==========

from Tkinter import Canvas, Tk, Label
import Image, ImageTk, ImageChops, ImageStat # PIL
import aggdraw
from random import randint
import time
import copy

FITNESS_OFFSET = 0
saved = [None, None]
def fitness(im1, im2):
    """Calculate a value derived from the root mean squared of the
difference
    between two images.  It is normalized so that when a black image
is
    compared with the original one (img1), the fitness given is 0, and
when the
    image is identical, the fitness value is 100."""
    global FITNESS_OFFSET
    stat = ImageStat.Stat(ImageChops.difference(im1, im2))
    fit = 1. - sum(stat.rms[:3])/(255*3)
    if FITNESS_OFFSET == 0:
        black_image = aggdraw.Draw("RGBA", im1.size, "black")
        s = black_image.tostring()
        raw = Image.fromstring('RGBA', im1.size, s)
        stat = ImageStat.Stat(ImageChops.difference(im1, raw))
        FITNESS_OFFSET = 1. - sum(stat.rms[:3])/(255*3)
    return 100*(fit-FITNESS_OFFSET)/(1.-FITNESS_OFFSET)

class DNA(object):
    def __init__(self, width, height, polygons=50, edges=6):
        self.polygons = polygons
        self.edges = edges
        self.width = width
        self.height = height
        self.dna = []

    def init_dna(self):
        for i in range(self.polygons):
            self.dna.append(self.random_polygon())

    def random_polygon(self):
        edges = []
        for i in range(self.edges):
            edges.append(randint(0, self.width))
            edges.append(randint(0, self.height))
        col = [randint(0, 255), randint(0, 255), randint(0, 255),
randint(0, 255)]
        return edges, col

    def mutate(self):
        selected = randint(0, self.polygons-1)
        _type = randint(0, 2)
        if _type == 0: # colour
            col_index = randint(0, 3)
            self.dna[selected][1][col_index] = randint(0, 255)
        elif _type == 1: # x coordinate
            coord = randint(0, self.edges-1)
            self.dna[selected][0][2*coord] = randint(0, self.width)
        elif _type == 2: # y coordinate
            coord = randint(0, self.edges-1)
            self.dna[selected][0][2*coord+1] = randint(0, self.height)

class AggDrawCanvas(Canvas):
    def __init__(self, width, height, win):
        Canvas.__init__(self, win)
        self.image_id = None
        self.win = win
        self._width = width
        self._height = height
        self._size = width, height
        self.config(width=width, height=height+20)
        self.info = self.create_text(width/2, height+20)
        self.pack()
        self.dna = DNA(self._width, self._height)
        self.mutations = 0

    def draw_dna(self):
        img = Image.new("RGBA", self._size, "black")
        self.context = aggdraw.Draw(img)
        for gene in self.dna.dna:
            brush = aggdraw.Brush(tuple(gene[1][0:3]), opacity=gene[1]
[3])
            self.context.polygon(gene[0], brush)
        self.delete(img)
        self.redraw()

    def redraw(self):
        self.mutations += 1
        s = self.context.tostring()
        self.delete(self.context)
        raw = Image.fromstring('RGBA', self._size, s)
        self.fitness = fitness(mona_lisa, raw)
        self.itemconfig(self.info,
                        text="%2.2f  %d"%(self.fitness,
self.mutations),
                        fill="black")
        self.image = ImageTk.PhotoImage(raw)
        self.delete(self.image_id)
        self.image_id = self.create_image(self._width/2, self._height/
2, image=self.image)
        self.update()

win = Tk()

mona_lisa = Image.open("mona_lisa.png")
img = ImageTk.PhotoImage(mona_lisa)

original_image = Canvas(win)
original_image.pack()
fitness_label = Label(win)

_w, _h = img.width(), img.height()
original_image.config(width=_w, height=_h)
original_image.create_image(_w/2, _h/2, image=img)

best_fit = AggDrawCanvas(_w, _h, win)
best_fit.dna.dna = []
best_fit.draw_dna()

current_fit = AggDrawCanvas(_w, _h, win)
current_fit.dna.init_dna()
current_fit.draw_dna()

while True:
    current_fit.dna.mutate()
    current_fit.draw_dna()
    if current_fit.fitness > best_fit.fitness:
        best_fit.dna.dna = copy.deepcopy(current_fit.dna.dna)
        best_fit.draw_dna()
    else:
        current_fit.dna.dna = copy.deepcopy(best_fit.dna.dna)

if __name__ == '__main__':
    win.mainloop()



More information about the Python-list mailing list