You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

CustomTkinter医学图像分割GUI中U-Net预测分割掩码显示失败及报错解决求助

CustomTkinter医学图像分割GUI中U-Net预测分割掩码显示失败及报错解决求助

我目前正在用CustomTkinter开发一个医学图像分割的可视化GUI,核心需求是:点击加载按钮导入医学图像切片文件夹,用预先训练好并保存为unet_model.h5的U-Net模型生成分割掩码,最后在界面里同时展示原始切片和对应的预测掩码,方便医生查看结果。

但现在遇到了棘手的问题:预测的分割掩码完全显示不出来,还直接抛出了Tkinter的回调错误,完整报错信息如下:

Exception in Tkinter callback
Traceback (most recent call last):
  File "C:\Users\maria\anaconda3\Lib\tkinter\__init__.py", line 1948, in __call__
    return self.func(*args)
  ^^^^^^^^^^^^^^^^
  File "C:\Users\maria\anaconda3\Lib\site-packages\customtkinter\windows\widgets\ctk_button.py", line 554, in _clicked
    self._command()
  File "C:\Users\maria\AppData\Local\Temp\ipykernel_27908\467682517.py", line 141, in loadimg
    segment_volume(pasta)
  File "C:\Users\maria\AppData\Local\Temp\ipykernel_27908\467682517.py", line 131, in segment_volume
    show_slice(current_slice)
  File "C:\Users\maria\AppData\Local\Temp\ipykernel_27908\467682517.py", line 93, in show_slice
    img_label.configure(image=img_label._image_ref)
  File "C:\Users\maria\anaconda3\Lib\site-packages\customtkinter\windows\widgets\ctk_label.py", line 222, in configure
    self._update_image()
  File "C:\Users\maria\anaconda3\Lib\site-packages\customtkinter\windows\widgets\ctk_label.py", line 144, in _update_image
    self._label.configure(image=self._image)
  File "C:\Users\maria\anaconda3\Lib\tkinter\__init__.py", line 1702, in configure
    return self._configure('configure', cnf, kw)
  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "C:\Users\maria\anaconda3\Lib\tkinter\__init__.py", line 1692, in _configure
    self.tk.call(_flatten((self._w, cmd)) + self._options(cnf))
_tkinter.TclError: image "pyimage7" doesn't exist

我的代码逻辑大致是:点击加载按钮后读取文件夹里的医学切片,用模型预测生成掩码,然后通过show_slice函数把原始图和掩码显示在CustomTkinter的Label组件里。但错误正好触发在show_slice更新Label图像的步骤,下面是我相关的核心代码片段:

模型加载与全局变量定义

import os
import cv2
import numpy as np
from tensorflow.keras.models import load_model
import customtkinter
from tkinter import filedialog
from PIL import Image, ImageTk

# 预加载U-Net模型
MODEL_PATH = "unet_model.h5"
model = load_model(MODEL_PATH, compile=False)

# 全局变量:存储测试切片、预测结果和显示用的Label组件
current_slice = 0
Xtest_global = None
preds_global = None
img_label = None
mask_label = None

错误触发的核心函数:show_slice

def show_slice(index):
    global img_label, mask_label
    if Xtest_global is None or preds_global is None:
        return
    
    # 处理原始切片并转换为Tkinter可用的图像格式
    img = (Xtest_global[index].squeeze() * 255).astype(np.uint8)
    img_pil = Image.fromarray(img)
    img_tk = ImageTk.PhotoImage(img_pil)
    img_label._image_ref = img_tk
    img_label.configure(image=img_label._image_ref)
    
    # 处理预测掩码并转换为Tkinter可用的图像格式
    mask = (preds_global[index].squeeze() * 255).astype(np.uint8)
    mask_pil = Image.fromarray(mask)
    mask_tk = ImageTk.PhotoImage(mask_pil)
    mask_label._image_ref = mask_tk
    mask_label.configure(image=mask_label._image_ref)

切片加载与分割预测函数

# 自然排序文件名的辅助函数
def natural_key(string_):
    import re
    return [int(s) if s.isdigit() else s for s in re.split(r'(\d+)', string_)]

# 图像预处理:调整大小并补边到指定尺寸
def resize_and_pad(img, size):
    desired_size = size[0]
    old_size = img.shape[:2]
    if old_size[0] == 0 or old_size[1] == 0:
        print("Warning: Image with zero dimensions. Skip")
        return None
    ratio = float(desired_size) / max(old_size)
    new_size = tuple([int(x*ratio) for x in old_size])
    if new_size[0] == 0 or new_size[1] == 0:
        print("Warning: Redimensioning with zero dimensions. Skip")
        return None
    img_resized = cv2.resize(img, (new_size[1], new_size[0]))
    delta_w = desired_size - new_size[1]
    delta_h = desired_size - new_size[0]
    top, bottom = delta_h//2, delta_h-(delta_h//2)
    left, right = delta_w//2, delta_w-(delta_w//2)
    color = [0, 0, 0]
    new_img = cv2.copyMakeBorder(img_resized, top, bottom, left, right, cv2.BORDER_CONSTANT, value=color)
    return new_img

# 加载测试集切片
def load_test_volume(test_folder, img_size=(256, 256), downsample_factor=1):
    slice_folder = os.path.join(test_folder)
    slice_files = sorted(
        [f for f in os.listdir(slice_folder) if f.endswith(('.tif', '.png'))],
        key=natural_key
    )
    slices = []
    for slice_file in slice_files:
        slice_path = os.path.join(slice_folder, slice_file)
        img = cv2.imread(slice_path, cv2.IMREAD_GRAYSCALE)
        if img is None:
            print(f"Warning: impossible to read the image {slice_path}. Skip")
            continue
        img = cv2.resize(img, (0, 0), fx=downsample_factor, fy=downsample_factor, interpolation=cv2.INTER_LINEAR)
        img = resize_and_pad(img, img_size)
        if img is None:
            continue
        slices.append(img)
    return slices

# 对整个文件夹的切片执行分割预测
def segment_volume(folder_path):
    global Xtest_global, preds_global, current_slice
    slice_imgs = load_test_volume(folder_path, downsample_factor=1)
    if len(slice_imgs) == 0:
        print("None valid image found in the folder")
        return
    # 预处理为模型输入格式
    X_slices = [img[..., np.newaxis] / 255.0 for img in slice_imgs]
    Xtest_global = np.array(X_slices)
    # 模型预测
    preds_global = model.predict(Xtest_global, verbose=1)
    # 显示第一张切片
    current_slice = 0
    show_slice(current_slice)

GUI入口回调函数

def loadimg():
    pasta = filedialog.askdirectory()
    if not pasta:
        return
    segment_volume(pasta)

# 省略CustomTkinter窗口初始化、Label与按钮创建代码
# 大致逻辑:创建窗口,添加img_label/mask_label用于显示图像,加载按钮绑定loadimg函数

我尝试过把ImageTk对象存在Label的_image_ref属性里防止被垃圾回收,但还是出现了image "pyimage7" doesn't exist的错误,完全搞不懂问题出在哪,有没有大佬能帮我排查一下问题根源或者给个解决思路?


内容来源于stack exchange

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.07 08:24:51