0

I'm using CustomTkinter to build a GUI for medical image segmentation. I have a button to load the images, and I’ve previously saved my trained model as "unet_model.h5". I want to display the predicted segmentation masks in the interface so that doctors can visualize the segmentations, but they currently don’t appear. Instead, I get the following error:

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

This is the code I tried:

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

#Pre-processing before segmentation
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

#Load model 

MODEL_PATH = "unet_model.h5"
model = load_model(MODEL_PATH, compile=False)

current_slice = 0
Xtest_global = None
preds_global = None
img_label = None
mask_label = None


def show_slice(index):
    global img_label, mask_label

    if Xtest_global is None or preds_global is None:
        return

    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)

    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 next_slice():
    global current_slice
    if Xtest_global is None:
        return
    if current_slice < len(Xtest_global)-1:
        current_slice += 1
        show_slice(current_slice)

def prev_slice():
    global current_slice
    if Xtest_global is None:
        return
    if current_slice > 0:
        current_slice -= 1
        show_slice(current_slice)

#Segmentation

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) > 0.5).astype("int32")

    current_slice = 0
    show_slice(current_slice)

    prev_btn.configure(state="normal")
    next_btn.configure(state="normal")

#Load images

def loadimg():
    pasta = filedialog.askdirectory()
    if pasta:
        print("Selected folder", pasta)
        segment_volume(pasta)

customtkinter.set_appearance_mode("light")
customtkinter.set_default_color_theme("dark-blue")

root = customtkinter.CTk()
root.geometry("900x600")

frame_top = customtkinter.CTkFrame(master=root)
frame_top.pack(pady=10, padx=10, fill="x")

label = customtkinter.CTkLabel(master=frame_top, text="Segmentator OCT- Retina", font=("Roboto", 24))
label.pack(pady=12)

botao = customtkinter.CTkButton(master=frame_top, text="Load OCT Volume", command=loadimg)
botao.pack(pady=5)

frame_imgs = customtkinter.CTkFrame(master=root)
frame_imgs.pack(pady=10, padx=10, fill="both", expand=True)

img_label = customtkinter.CTkLabel(master=frame_imgs)
img_label.pack(side="left", padx=10, pady=10)

mask_label = customtkinter.CTkLabel(master=frame_imgs)
mask_label.pack(side="right", padx=10, pady=10)

frame_nav = customtkinter.CTkFrame(master=root)
frame_nav.pack(pady=10)

prev_btn = customtkinter.CTkButton(master=frame_nav, text="Anterior", command=prev_slice, state="disabled")
prev_btn.pack(side="left", padx=20)

next_btn = customtkinter.CTkButton(master=frame_nav, text="Próximo", command=next_slice, state="disabled")
next_btn.pack(side="right", padx=20)

root.mainloop()
4
  • Maybe first use print() (and print(type(...)), print(len(...)), etc.) to see which part of code is executed and what you really have in variables. It is called "print debugging" and it helps to see what code is really doing. Commented Aug 30 at 14:24
  • error suggests that image was removed from memory. You could debug code to see where it could be removed. Maybe it was assigned to variable which is not global and tkinter removed it (because there is bug in ImageTk.PhotoImage) Commented Aug 30 at 14:26
  • to run and test code it needs model. If you would reduce code and remove model or use fake values in place of model then we could test it. Commented Aug 30 at 14:39
  • I used fake values instead of model and prediction and I can't reproduce your problem. I see only warnings that CTkLabel prefers CTkImage instead of ImageTk.PhotoImage Commented Aug 30 at 14:51

0

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.