首页 > 解决方案 > Tkinter:图像循环减慢

问题描述

我编写了一个 Tkinter GUI,它应该通过循环遍历每个 3D 图像的 2D 切片来显示显示 3D 图像。我阅读了如何实现这样的图像循环,建议使用after()递归函数。原则上,这是我的实现:

def load_image(self):
    self.stack = read_3D_image(path)
    slice = self.stack[self.slice_no]
    im = Image.fromarray(slice)
    self.photo = ImageTk.PhotoImage(image=im)
    self.canvas.create_image(0, 0, image=self.photo, anchor=tk.NW)
    if self.forward is True:
        self.slice_no += 1
        if self.slice_no == 21:
            self.forward = False
    if self.forward is False:
        self.slice_no -= 1
        if self.slice_no == 0:
            self.forward = True
    root.after(10, self.load_image)

这在一段时间内运行良好,但几分钟后,循环明显变慢。我想这是因为迭代次数多。有没有办法来解决这个问题?

编辑:我注意到这一点:当程序运行时,图像循环将在大约 10 分钟后减慢到原始频率的一半左右。当我运行第二个实例时,它的循环运行同样慢。然后当我关闭第一个实例时,第二个实例循环立即运行得更快。我从 Eclipse 启动。

更新了完整代码

import glob
import os.path
import tkinter as tk
from PIL import Image, ImageTk
import numpy as np

import helpers


class App():

    def __init__(self, master):
        super().__init__()
        self.frame = tk.Frame(master)
        master.bind("<KP_1>", lambda e: self.is_cell())
        master.bind("<KP_2>", lambda e: self.is_not_cell())
        self.frame.pack()

        self.goto_button = tk.Button(
            self.frame, text="Go to:", command=self.goto)
        self.goto_button.pack(side=tk.TOP)

        self.goto_entry = tk.Entry(self.frame, width=5)
        self.goto_entry.pack(side=tk.TOP)

        self.img_side_length = 100

        self.canvas = tk.Canvas(
            master=self.frame, width=self.img_side_length, height=self.img_side_length)
        self.canvas.pack()

        self.img_label = tk.Label(self.frame, text="Bla")
        self.img_label.pack(side=tk.TOP)

        self.no_cell_button = tk.Button(
            self.frame, text="2: Not cell!", command=self.is_not_cell)
        self.no_cell_button.pack(side=tk.RIGHT)

        self.cell_button = tk.Button(
            self.frame, text="1: Cell!", command=self.is_cell)
        self.cell_button.pack(side=tk.RIGHT)



        self.img_path = "/storage/images/"
        self.img_list = glob.glob(os.path.join(self.img_path, "*"))
        self.img_list.sort()
        self.slice_no = 0
        self.img_no = 0
        self.forward = True
        self.no_of_imgs = len(self.img_list)
        self.stack = []
        self.image_id = self.canvas.create_image(0, 0, anchor=tk.NW)
        self.stack = helpers.read_image_sequence(self.img_list[self.img_no])

        self.classifications = np.zeros(self.no_of_imgs)

        self.out_path = "/dev/null"

        self.loop_image()

    def loop_image(self):

        data = self.stack[self.slice_no]
        im = Image.fromarray(data)
        im = im.resize((self.img_side_length, self.img_side_length))
        self.photo = ImageTk.PhotoImage(image=im)
        self.canvas.itemconfigure(self.image_id, image=self.photo)
        if self.forward is True:
            self.slice_no += 1
            if self.slice_no == 21:
                self.forward = False
        if self.forward is False:
            self.slice_no -= 1
            if self.slice_no == 0:
                self.forward = True
        root.after(10, self.loop_image)

    def next_image(self):
        self.img_no += 1
        self.stack = helpers.read_image_sequence(self.img_list[self.img_no])
        self.img_label['text'] = self.img_list[self.img_no].split("/")[-1]

    def previous_image(self):
        self.img_no -= 1
        self.stack = helpers.read_image_sequence(self.img_list[self.img_no])
        self.img_label['text'] = self.img_list[self.img_no].split("/")[-1]

    def is_cell(self):
        self.classifications[self.img_no] = 1
        with open(self.out_path, "a") as f:
            f.write(str(self.img_no) + "," + str(1) + "\n")
        print(self.classifications)
        self.next_image()

    def is_not_cell(self):
        self.classifications[self.img_no] = 2
        with open(self.out_path, "a") as f:
            f.write(str(self.img_no) + "," + str(2) + "\n")
        print(self.classifications)
        self.next_image()


    def goto(self):
        self.img_no = int(self.goto_entry.get())


root = tk.Tk()

app = App(root)

root.mainloop()

标签: pythontkinter

解决方案


您每秒创建 100 个图像并将它们堆叠在一起。10 分钟后,60,000 张图像堆叠在一起。当画布上有数以万计的项目时,即使只有一个是不可见的,画布也会出现性能问题。

无需在画布上创建越来越多的图像,只需修改现有图像:

def __init__(self):
    ...
    self.canvas = tk.Canvas(...)
    ...
    # create the image object which will display the image
    self.image_id = self.canvas.create_image(0, 0, anchor=tk.NW)

def load_image(self):
    ...
    self.photo = ImageTk.PhotoImage(image=im)

    # reconfigure the canvas item to show the new image
    canvas.itemconfigure(self.image_id, image=self.photo)
    ...

推荐阅读