Memory leak problem (while using tkinter)

A

André

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

Marc 'BlackJack' Rintsch

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.

I don't see anything obvious but that the program is too long and uses
too much components to be sure that `Tkinter` is the culprit. Try too
trim it down to the smallest possible program that still has the problem.

Ciao,
Marc 'BlackJack' Rintsch
 
A

André

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-mo...
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 onhttp://alteredqualia.com/visualization/evolve/)
that is saved under "mona_lisa.png".


It appears that the problem occurred due to creating drawing
"contexts" with aggdraw which became orphaned in some ways. Below is
some changes that appear to solve the problem. Perhaps this will be
useful to others at some point...

André


[SNIP]
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

self.img = None
    def draw_dna(self):
        img = Image.new("RGBA", self._size, "black")
        self.context = aggdraw.Draw(img)

replace by:

if self.img is None:
self.img = Image.new("RGBA", self._size, "black")
self.context = aggdraw.Draw(self.img)
else:
brush = aggdraw.Brush((0, 0, 0), opacity=255)
self.context.rectangle((0, 0, self._width, self._height),
brush)



        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()
[SNIP]
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,744
Messages
2,569,483
Members
44,901
Latest member
Noble71S45

Latest Threads

Top