Solved. was: Memory leak problem (while using tkinter)

2008-12-31 Thread André
On Dec 31, 12:21 am, André  wrote:
> 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]
--
http://mail.python.org/mailman/listinfo/python-list


Re: Memory leak problem (while using tkinter)

2008-12-31 Thread Marc 'BlackJack' Rintsch
On Tue, 30 Dec 2008 20:21:06 -0800, André wrote:

> 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
--
http://mail.python.org/mailman/listinfo/python-list


Memory leak problem (while using tkinter)

2008-12-30 Thread 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()
--
http://mail.python.org/mailman/listinfo/python-list