Memory leak problem (while using tkinter)

Discussion in 'Python' started by André, Dec 31, 2008.

  1. André

    André Guest

    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()
     
    André, Dec 31, 2008
    #1
    1. Advertising

  2. 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
     
    Marc 'BlackJack' Rintsch, Dec 31, 2008
    #2
    1. Advertising

  3. André

    André Guest

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

    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]
     
    André, Dec 31, 2008
    #3
    1. Advertising

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

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Ton K.
    Replies:
    0
    Views:
    365
    Ton K.
    Jul 25, 2003
  2. Elbert Lev

    Memory leak in Tkinter?????

    Elbert Lev, Jul 23, 2004, in forum: Python
    Replies:
    2
    Views:
    330
    Elbert Lev
    Jul 25, 2004
  3. Prashant
    Replies:
    2
    Views:
    311
    jacob navia
    Jun 30, 2004
  4. s.subbarayan

    Dynamic memory allocation and memory leak...

    s.subbarayan, Mar 18, 2005, in forum: C Programming
    Replies:
    10
    Views:
    707
    Eric Sosman
    Mar 22, 2005
  5. frikk
    Replies:
    3
    Views:
    322
    frikk
    Aug 3, 2007
Loading...

Share This Page