I'm attempting to create a series of canvases, each displaying a different section of an image according to the coordinates present in a list. The number of different coordinates is dynamic so it must be done in a loop.
The issue I am having is even though I'm saving my references garbage collection is preventing all canvases except the last from displaying an image.
Here is what I have so far:
import tkinter as tk
import cv2
from PIL import Image, ImageTk
class App(object):
def __init__(self):
self.root = tk.Tk()
# Candidates holds the coordinates for the image sections, and is hardcoded for this example
candidates = [[0,100,100,100], [15,15,200,200], [30,30,200,200], [50,50,200,200], [100,100,200,200], [200,200,200,200]]
self.im = cv2.imread(r"....")
j = 0
i = 0
frames = []
images = []
refs = []
for candidate in candidates:
x,y,w,h = tuple(candidate)
self.img_tk = ImageTk.PhotoImage(Image.fromarray(self.im[y:y h, x:x w]))
Frame = tk.Canvas(self.root,bg='white', highlightthickness=1, highlightbackground="black", width=100, height= 100)
Frame.grid(row = i, column = j, sticky = 'w, e, n, s', padx=5, pady=5)
ref = Frame.create_image(0, 0, image=self.img_tk, anchor="nw")
images.append(self.img_tk)
refs.append(ref)
frames.append(Frame)
if j<2:
j =1
else:
j=0
i =1
app = App()
app.root.mainloop()
and the result:
As you can see, only the last frame in the loop has an image created. Any thoughts are greatly appreciated, thanks.
CodePudding user response:
It is because images
is a local variable, so it will be garbage collected after the function exits, so are the image references stored in it. The last image can be shown because self.img_tk
saves the reference.
To solve it, change images
to instance variable self.images
.