"_tkinter.TclError: too many nested evaluations" in Classification GUI
"_tkinter.TclError: too many nested evaluations" in Classification GUI
请帮帮我,我快疯了...
目标:
一个显示图像的 GUI,三个用于将显示的图像保存在“好”、“坏”和“不确定”文件夹中的按钮,以及一个用于退出应用程序的附加按钮。
详情:
显示的图片被不应应用于已保存图像的功能更改(这很好用!)。按下按钮时,显示的图片应保存到特定文件夹,然后显示下一张图像。图片名称来自pandas df的列表,其中它们的根文件夹路径必须在252、504和756张图片(“ROOT_PICTURE_PATH_X”)之后更改。
问题:
当我 运行 代码一切正常时,直到我到达图像 249 然后程序停止并显示以下错误消息并且 tkinter window 停止工作。
Exception in Tkinter callback
Traceback (most recent call last):
File "/home/sizimmermann/anaconda3/envs/testlab_1/lib/python3.9/tkinter/__init__.py", line 1892, in __call__
return self.func(*args)
File "/tmp/ipykernel_20993/382054037.py", line 128, in <lambda>
command=lambda: good(local_img_path)
File "/tmp/ipykernel_20993/382054037.py", line 110, in good
ROOT.title(
File "/home/sizimmermann/anaconda3/envs/testlab_1/lib/python3.9/tkinter/__init__.py", line 2226, in wm_title
return self.tk.call('wm', 'title', self._w, string)
_tkinter.TclError: too many nested evaluations (infinite loop?)
我的假设:
我没有正确设置 tkinter window 并且 root.title 重叠或类似的东西。不过,这是我第一次使用 tkinter。
附加问题:
我是否在程序末尾正确编程了根文件夹的更改,还是必须在主循环中插入“ROOT_PICTURE_PATHS”?
代码:
import cv2 as cv
import tkinter as tk
import os
import pandas as pd
from PIL import Image as Pimage
from PIL import ImageTk
# change the 'init_path' to the location where you unpacked this project
INIT_PATH = '/media/sf_shared_folder/04_coding/99_pipeline'
ROOT_IMG_PATH = os.path.join(INIT_PATH, '03_sorted_data')
CLASSIFIED_IMG_PATH = os.path.join(ROOT_IMG_PATH, 'classified_images')
GOOD_IMG_PATH = os.path.join(CLASSIFIED_IMG_PATH,'good')
BAD_IMG_PATH = os.path.join(CLASSIFIED_IMG_PATH,'bad')
UNSURE_IMG_PATH =os.path.join(CLASSIFIED_IMG_PATH,'unsure')
ROOT_PICTURE_PATH_1 = os.path.join(
ROOT_IMG_PATH,'20220405/133107_MEASUREMENT_complete/ROIs'
)
ROOT_PICTURE_PATH_2 = os.path.join(
ROOT_IMG_PATH,'20220405/152317_MEASUREMENT_complete/ROIs'
)
ROOT_PICTURE_PATH_3 = os.path.join(
ROOT_IMG_PATH,'20220408/093417_MEASUREMENT_complete/ROIs'
)
ROOT_PICTURE_PATH_4 = os.path.join(
ROOT_IMG_PATH,'20220411/082727_MEASUREMENT_complete/ROIs'
)
data = pd.read_csv(os.path.join(ROOT_IMG_PATH, 'main_raw_data.csv'))
# extract a list with 'PostProcessPicturePath'
PPP = data[['PostProcessPicturePath']]
# PPP.head(1)
counter = 0
classification_list = []
def img_manipulation(local_image_to_manipulate):
img = cv.imread(local_image_to_manipulate)
imgray = cv.cvtColor(img, cv.COLOR_BGR2GRAY)
ret, thresh = cv.threshold(imgray, 127, 255, 0)
contours, hierarchy = cv.findContours(
thresh,
cv.RETR_TREE,
cv.CHAIN_APPROX_SIMPLE
)
cv.drawContours(img, [contours[0]], 0, (0,255,0), 1)
img = cv.resize(img, (650,650))
img = Pimage.fromarray(img)
local_imgtk = ImageTk.PhotoImage(image=img)
# local_imgtk = ImageTk.PhotoImage(
# Pimage.open(local_image_to_manipulate)
# ) # image=img
return(local_imgtk)
def init_ui(local_img_path):
global BTN_P_BAD
global BTN_P_GOOD
global BTN_P_UNSURE
global BTN_P_QUIT
global classification_list
global counter
global img_label
global PPP
global ROOT
img_name = PPP.iat[counter,0]
ROOT = tk.Tk()
str_counter = str(counter)
ROOT.title(
'Image Classification for: '+img_name+ ' Counter: '+str_counter+ 'of 1008'
)
first_img_path=os.path.join(local_img_path, img_name)
start_image = img_manipulation(first_img_path)
img_label = tk.Label(image=start_image)
img_label.grid(row=0, column=0, columnspan=4)
def good(local2_img_path):
global BTN_P_BAD
global BTN_P_GOOD
global BTN_P_UNSURE
global counter
global classification_list
global GOOD_IMG_PATH
global img_label
global img_name
global PPP
global ROOT
# print('\n counter by button press: ', counter)
img_name = PPP.iat[counter,0]
if counter == 0:
img_2_save = Pimage.open(first_img_path)
image_save_string = os.path.join(
GOOD_IMG_PATH,
str('1_'+first_img_path[-19:])
)
else:
current_img_path = os.path.join(local2_img_path, img_name)
img_2_save = Pimage.open(current_img_path)
image_save_string = os.path.join(
GOOD_IMG_PATH,
str('1_'+current_img_path[-19:])
)
image_save_string = image_save_string
img_2_save.save(image_save_string)
counter +=1
# img_label.grid_forget()
img_name = PPP.iat[counter,0]
str_counter = str(counter)
ROOT.title(
'Image Classification for: '+img_name+ ' Counter: '+str_counter+ 'of 1008'
)
next_img_path=os.path.join(local2_img_path, img_name)
next_imgtk = img_manipulation(next_img_path)
img_label = tk.Label(image = next_imgtk)
img_label.grid(row=0, column=0, columnspan=4)
classification_list.append(1)
print('\n counter after if: ', counter)
# print(len(classification_list))
BTN_P_GOOD = tk.Button(
ROOT,
text="good or '->'",
fg='green',
font='bold',
justify="center",
activebackground='green',
command=lambda: good(local_img_path)
)
BTN_P_GOOD.grid(row=1,column=3)
BTN_P_BAD = tk.Button(
ROOT,
text="bad or '<-'",
fg='red',
font ='bold',
justify="center",
activebackground='red',
command=lambda: bad(local_img_path)
)
BTN_P_BAD.grid(row=1,column=1)
BTN_P_UNSURE = tk.Button(
ROOT,
text="unsure",
fg='gray',
font ='bold',
justify="center",
activebackground='orange',
command=lambda: unsure(local_img_path)
)
BTN_P_UNSURE.grid(row=1,column=2)
ROOT.mainloop()
return
def bad(local2_img_path):
global BAD_IMG_PATH
global BTN_P_BAD
global BTN_P_GOOD
global BTN_P_UNSURE
global counter
global classification_list
global img_label
global img_name
global PPP
global ROOT
img_name = PPP.iat[counter,0]
if counter == 0:
img_2_save = Pimage.open(first_img_path)
image_save_string = os.path.join(
BAD_IMG_PATH,
str('0_'+first_img_path[-19:])
)
else:
current_img_path = os.path.join(local2_img_path, img_name)
img_2_save = Pimage.open(current_img_path)
image_save_string = os.path.join(
BAD_IMG_PATH,
str('0_'+current_img_path[-19:])
)
img_2_save.save(image_save_string)
counter +=1
img_label.grid_forget()
img_name = PPP.iat[counter,0]
str_counter = str(counter)
ROOT.title(
'Image Classification for: '+img_name+ ' Counter: '+str_counter+ 'of 1008'
)
next_img_path=os.path.join(local2_img_path, img_name)
next_imgtk = img_manipulation(next_img_path)
img_label = tk.Label(image = next_imgtk)
img_label.grid(row=0, column=0, columnspan=4)
classification_list.append(0)
BTN_P_GOOD = tk.Button(
ROOT,
text="good or '->'",
fg='green',
font='bold',
justify="center",
activebackground='green',
command=lambda: good(local_img_path)
)
BTN_P_GOOD.grid(row=1,column=3)
BTN_P_BAD = tk.Button(
ROOT,
text="bad or '<-'",
fg='red',
font ='bold',
justify="center",
activebackground='red',
command=lambda: bad(local_img_path)
)
BTN_P_BAD.grid(row=1,column=1)
BTN_P_UNSURE = tk.Button(
ROOT,
text="unsure",
fg='gray',
font ='bold',
justify="center",
activebackground='orange',
command=lambda: unsure(local_img_path)
)
BTN_P_UNSURE.grid(row=1,column=2)
ROOT.mainloop()
return
def unsure(local2_img_path):
global BTN_P_BAD
global BTN_P_GOOD
global BTN_P_UNSURE
global counter
global classification_list
global img_label
global img_name
global PPP
global ROOT
global UNSURE_IMG_PATH
img_name = PPP.iat[counter,0]
if counter == 0:
img_2_save = Pimage.open(first_img_path)
image_save_string = os.path.join(
UNSURE_IMG_PATH,
str('2_'+first_img_path[-19:])
)
else:
# ROOT.title('Image Classification for: '+img_name)
current_img_path = os.path.join(local2_img_path, img_name)
img_2_save = Pimage.open(current_img_path)
image_save_string = os.path.join(
UNSURE_IMG_PATH,
str('2_'+current_img_path[-19:])
)
img_2_save.save(image_save_string)
counter +=1
img_label.grid_forget()
img_name = PPP.iat[counter,0]
str_counter = str(counter)
ROOT.title(
'Image Classification for: '+img_name+ ' Counter: '+str_counter+ 'of 1008'
)
next_img_path=os.path.join(local2_img_path, img_name)
next_imgtk = img_manipulation(next_img_path)
img_label = tk.Label(image = next_imgtk)
img_label.grid(row=0, column=0, columnspan=4)
classification_list.append(2)
BTN_P_GOOD = tk.Button(
ROOT,
text="good or '->'",
fg='green',
font='bold',
justify="center",
activebackground='green',
command=lambda: good(local_img_path)
)
BTN_P_GOOD.grid(row=1,column=3)
BTN_P_BAD = tk.Button(
ROOT,
text="bad or '<-'",
fg='red',
font ='bold',
justify="center",
activebackground='red',
command=lambda: bad(local_img_path)
)
BTN_P_BAD.grid(row=1,column=1)
BTN_P_UNSURE = tk.Button(
ROOT,
text="unsure",
fg='gray',
font ='bold',
justify="center",
activebackground='orange',
command=lambda: unsure(local_img_path)
)
BTN_P_UNSURE.grid(row=1,column=2)
ROOT.mainloop()
return
BTN_P_GOOD = tk.Button(
ROOT,
text="good or '->'",
fg='green',
font='bold',
justify="center",
activebackground='green',
command=lambda: good(local_img_path)
)
BTN_P_BAD = tk.Button(
ROOT,
text="bad or '<-'",
fg='red',
font ='bold',
justify="center",
activebackground='red',
command=lambda: bad(local_img_path)
)
BTN_P_UNSURE = tk.Button(
ROOT,
text="unsure",
fg='gray',
font ='bold',
justify="center",
activebackground='orange',
command=lambda: unsure(local_img_path)
)
BTN_P_QUIT = tk.Button(
ROOT,
text="QUIT",
fg='red',
font ='bold',
justify="center",
activebackground='red',
command = lambda: ROOT.destroy()
)
BTN_P_BAD.grid(row=1,column=1)
BTN_P_GOOD.grid(row=1,column=3)
BTN_P_UNSURE.grid(row=1,column=2)
BTN_P_QUIT.grid(row=1,column=4)
print('\n *** Mainloop start *** \n')
# ROOT.after(2000, lambda: ROOT.destroy())
ROOT.mainloop()
print(
'************************************************* \n' +
'*** Please classify the Pictures in the GUI. ***' +
'\n *************************************************')
try:
os.mkdir(CLASSIFIED_IMG_PATH)
os.mkdir(GOOD_IMG_PATH)
os.mkdir(BAD_IMG_PATH)
os.mkdir(UNSURE_IMG_PATH)
print(
'*** Folder classified images created in:\n',
CLASSIFIED_IMG_PATH,
' ***'
)
except OSError:
pass
if counter == 0:
init_ui(ROOT_PICTURE_PATH_1)
print('First batch samples classified.')
elif counter == 252:
init_ui(ROOT_PICTURE_PATH_1)
print('Second batch samples classified.')
elif counter == 504:
init_ui(ROOT_PICTURE_PATH_1)
print('Third batch samples classified.')
elif counter == 756:
init_ui(ROOT_PICTURE_PATH_1)
print('\n *** Classification completed. ***')
所以你的问题的根本原因是你 re-entrantly 调用 mainloop
,这是一个 no-no.
总而言之,您的代码确实需要大量清理才能正常工作;因为我没有你的本地数据集,也不能完全推断出它在磁盘上的真实结构,这可能不是你想要的,但它应该能让你更接近。
我们的想法是,您构建基础 UI 一次,然后在浏览图像时重新配置它。
import shutil
import sys
import cv2 as cv
import tkinter as tk
import os
import pandas as pd
from PIL import Image, ImageTk
# change the 'init_path' to the location where you unpacked this project
INIT_PATH = "/media/sf_shared_folder/04_coding/99_pipeline"
ROOT_IMG_PATH = os.path.join(INIT_PATH, "03_sorted_data")
CLASSIFIED_IMG_PATH = os.path.join(ROOT_IMG_PATH, "classified_images")
def img_manipulation(local_image_to_manipulate):
img = cv.imread(local_image_to_manipulate)
imgray = cv.cvtColor(img, cv.COLOR_BGR2GRAY)
ret, thresh = cv.threshold(imgray, 127, 255, 0)
contours, hierarchy = cv.findContours(thresh, cv.RETR_TREE, cv.CHAIN_APPROX_SIMPLE)
cv.drawContours(img, [contours[0]], 0, (0, 255, 0), 1)
img = cv.resize(img, (650, 650))
img = Image.fromarray(img)
return ImageTk.PhotoImage(image=img)
class ImageClassificationApp:
def __init__(self, root, image_paths):
self.root = root
self.image_paths = list(image_paths)
self.current_image_index = 0
self.build_ui()
self.update_image()
def build_ui(self):
good_button = tk.Button(
self.root,
text="good or '->'",
fg="green",
font="bold",
justify="center",
activebackground="green",
command=lambda: self.mark_current("good"),
)
good_button.grid(row=1, column=3)
bad_button = tk.Button(
self.root,
text="bad or '<-'",
fg="red",
font="bold",
justify="center",
activebackground="red",
command=lambda: self.mark_current("bad"),
)
bad_button.grid(row=1, column=1)
unsure_button = tk.Button(
self.root,
text="unsure",
fg="gray",
font="bold",
justify="center",
activebackground="orange",
command=lambda: self.mark_current("unsure"),
)
unsure_button.grid(row=1, column=2)
quit_button = tk.Button(
self.root,
text="QUIT",
fg="red",
font="bold",
justify="center",
activebackground="red",
command=lambda: sys.exit(),
)
quit_button.grid(row=1, column=4)
img_label = tk.Label()
img_label.grid(row=0, column=0, columnspan=4)
self.img_label = img_label
@property
def current_image(self):
if self.current_image_index < len(self.image_paths):
return self.image_paths[self.current_image_index]
return None
def update_image(self):
img_name = self.current_image
if not img_name:
return # TODO: handle running out of images more gracefully
self.root.title(
f"Image Classification for: {img_name} Counter: {self.current_image_index} of {len(self.image_paths)} "
)
img_path = os.path.join(ROOT_IMG_PATH, img_name)
image = img_manipulation(img_path)
self.img_label.configure(image=image)
def mark_current(self, mark):
img_name = self.current_image
if not img_name:
return # TODO: handle running out of images more gracefully
dest_dir = os.path.join(CLASSIFIED_IMG_PATH, mark)
os.makedirs(dest_dir, exist_ok=True)
dest_path = os.path.join(dest_dir, img_name)
shutil.copy(os.path.join(ROOT_IMG_PATH, img_name), dest_path)
self.go_to_next_image()
def go_to_next_image(self):
self.current_image_index += 1
self.update_image()
def main():
data = pd.read_csv(os.path.join(ROOT_IMG_PATH, "main_raw_data.csv"))
paths = list(data["PostProcessPicturePath"].values)
root = tk.Tk()
app = ImageClassificationApp(root, paths)
root.mainloop()
if __name__ == "__main__":
main()
请帮帮我,我快疯了...
目标: 一个显示图像的 GUI,三个用于将显示的图像保存在“好”、“坏”和“不确定”文件夹中的按钮,以及一个用于退出应用程序的附加按钮。
详情: 显示的图片被不应应用于已保存图像的功能更改(这很好用!)。按下按钮时,显示的图片应保存到特定文件夹,然后显示下一张图像。图片名称来自pandas df的列表,其中它们的根文件夹路径必须在252、504和756张图片(“ROOT_PICTURE_PATH_X”)之后更改。
问题: 当我 运行 代码一切正常时,直到我到达图像 249 然后程序停止并显示以下错误消息并且 tkinter window 停止工作。
Exception in Tkinter callback
Traceback (most recent call last):
File "/home/sizimmermann/anaconda3/envs/testlab_1/lib/python3.9/tkinter/__init__.py", line 1892, in __call__
return self.func(*args)
File "/tmp/ipykernel_20993/382054037.py", line 128, in <lambda>
command=lambda: good(local_img_path)
File "/tmp/ipykernel_20993/382054037.py", line 110, in good
ROOT.title(
File "/home/sizimmermann/anaconda3/envs/testlab_1/lib/python3.9/tkinter/__init__.py", line 2226, in wm_title
return self.tk.call('wm', 'title', self._w, string)
_tkinter.TclError: too many nested evaluations (infinite loop?)
我的假设: 我没有正确设置 tkinter window 并且 root.title 重叠或类似的东西。不过,这是我第一次使用 tkinter。
附加问题: 我是否在程序末尾正确编程了根文件夹的更改,还是必须在主循环中插入“ROOT_PICTURE_PATHS”?
代码:
import cv2 as cv
import tkinter as tk
import os
import pandas as pd
from PIL import Image as Pimage
from PIL import ImageTk
# change the 'init_path' to the location where you unpacked this project
INIT_PATH = '/media/sf_shared_folder/04_coding/99_pipeline'
ROOT_IMG_PATH = os.path.join(INIT_PATH, '03_sorted_data')
CLASSIFIED_IMG_PATH = os.path.join(ROOT_IMG_PATH, 'classified_images')
GOOD_IMG_PATH = os.path.join(CLASSIFIED_IMG_PATH,'good')
BAD_IMG_PATH = os.path.join(CLASSIFIED_IMG_PATH,'bad')
UNSURE_IMG_PATH =os.path.join(CLASSIFIED_IMG_PATH,'unsure')
ROOT_PICTURE_PATH_1 = os.path.join(
ROOT_IMG_PATH,'20220405/133107_MEASUREMENT_complete/ROIs'
)
ROOT_PICTURE_PATH_2 = os.path.join(
ROOT_IMG_PATH,'20220405/152317_MEASUREMENT_complete/ROIs'
)
ROOT_PICTURE_PATH_3 = os.path.join(
ROOT_IMG_PATH,'20220408/093417_MEASUREMENT_complete/ROIs'
)
ROOT_PICTURE_PATH_4 = os.path.join(
ROOT_IMG_PATH,'20220411/082727_MEASUREMENT_complete/ROIs'
)
data = pd.read_csv(os.path.join(ROOT_IMG_PATH, 'main_raw_data.csv'))
# extract a list with 'PostProcessPicturePath'
PPP = data[['PostProcessPicturePath']]
# PPP.head(1)
counter = 0
classification_list = []
def img_manipulation(local_image_to_manipulate):
img = cv.imread(local_image_to_manipulate)
imgray = cv.cvtColor(img, cv.COLOR_BGR2GRAY)
ret, thresh = cv.threshold(imgray, 127, 255, 0)
contours, hierarchy = cv.findContours(
thresh,
cv.RETR_TREE,
cv.CHAIN_APPROX_SIMPLE
)
cv.drawContours(img, [contours[0]], 0, (0,255,0), 1)
img = cv.resize(img, (650,650))
img = Pimage.fromarray(img)
local_imgtk = ImageTk.PhotoImage(image=img)
# local_imgtk = ImageTk.PhotoImage(
# Pimage.open(local_image_to_manipulate)
# ) # image=img
return(local_imgtk)
def init_ui(local_img_path):
global BTN_P_BAD
global BTN_P_GOOD
global BTN_P_UNSURE
global BTN_P_QUIT
global classification_list
global counter
global img_label
global PPP
global ROOT
img_name = PPP.iat[counter,0]
ROOT = tk.Tk()
str_counter = str(counter)
ROOT.title(
'Image Classification for: '+img_name+ ' Counter: '+str_counter+ 'of 1008'
)
first_img_path=os.path.join(local_img_path, img_name)
start_image = img_manipulation(first_img_path)
img_label = tk.Label(image=start_image)
img_label.grid(row=0, column=0, columnspan=4)
def good(local2_img_path):
global BTN_P_BAD
global BTN_P_GOOD
global BTN_P_UNSURE
global counter
global classification_list
global GOOD_IMG_PATH
global img_label
global img_name
global PPP
global ROOT
# print('\n counter by button press: ', counter)
img_name = PPP.iat[counter,0]
if counter == 0:
img_2_save = Pimage.open(first_img_path)
image_save_string = os.path.join(
GOOD_IMG_PATH,
str('1_'+first_img_path[-19:])
)
else:
current_img_path = os.path.join(local2_img_path, img_name)
img_2_save = Pimage.open(current_img_path)
image_save_string = os.path.join(
GOOD_IMG_PATH,
str('1_'+current_img_path[-19:])
)
image_save_string = image_save_string
img_2_save.save(image_save_string)
counter +=1
# img_label.grid_forget()
img_name = PPP.iat[counter,0]
str_counter = str(counter)
ROOT.title(
'Image Classification for: '+img_name+ ' Counter: '+str_counter+ 'of 1008'
)
next_img_path=os.path.join(local2_img_path, img_name)
next_imgtk = img_manipulation(next_img_path)
img_label = tk.Label(image = next_imgtk)
img_label.grid(row=0, column=0, columnspan=4)
classification_list.append(1)
print('\n counter after if: ', counter)
# print(len(classification_list))
BTN_P_GOOD = tk.Button(
ROOT,
text="good or '->'",
fg='green',
font='bold',
justify="center",
activebackground='green',
command=lambda: good(local_img_path)
)
BTN_P_GOOD.grid(row=1,column=3)
BTN_P_BAD = tk.Button(
ROOT,
text="bad or '<-'",
fg='red',
font ='bold',
justify="center",
activebackground='red',
command=lambda: bad(local_img_path)
)
BTN_P_BAD.grid(row=1,column=1)
BTN_P_UNSURE = tk.Button(
ROOT,
text="unsure",
fg='gray',
font ='bold',
justify="center",
activebackground='orange',
command=lambda: unsure(local_img_path)
)
BTN_P_UNSURE.grid(row=1,column=2)
ROOT.mainloop()
return
def bad(local2_img_path):
global BAD_IMG_PATH
global BTN_P_BAD
global BTN_P_GOOD
global BTN_P_UNSURE
global counter
global classification_list
global img_label
global img_name
global PPP
global ROOT
img_name = PPP.iat[counter,0]
if counter == 0:
img_2_save = Pimage.open(first_img_path)
image_save_string = os.path.join(
BAD_IMG_PATH,
str('0_'+first_img_path[-19:])
)
else:
current_img_path = os.path.join(local2_img_path, img_name)
img_2_save = Pimage.open(current_img_path)
image_save_string = os.path.join(
BAD_IMG_PATH,
str('0_'+current_img_path[-19:])
)
img_2_save.save(image_save_string)
counter +=1
img_label.grid_forget()
img_name = PPP.iat[counter,0]
str_counter = str(counter)
ROOT.title(
'Image Classification for: '+img_name+ ' Counter: '+str_counter+ 'of 1008'
)
next_img_path=os.path.join(local2_img_path, img_name)
next_imgtk = img_manipulation(next_img_path)
img_label = tk.Label(image = next_imgtk)
img_label.grid(row=0, column=0, columnspan=4)
classification_list.append(0)
BTN_P_GOOD = tk.Button(
ROOT,
text="good or '->'",
fg='green',
font='bold',
justify="center",
activebackground='green',
command=lambda: good(local_img_path)
)
BTN_P_GOOD.grid(row=1,column=3)
BTN_P_BAD = tk.Button(
ROOT,
text="bad or '<-'",
fg='red',
font ='bold',
justify="center",
activebackground='red',
command=lambda: bad(local_img_path)
)
BTN_P_BAD.grid(row=1,column=1)
BTN_P_UNSURE = tk.Button(
ROOT,
text="unsure",
fg='gray',
font ='bold',
justify="center",
activebackground='orange',
command=lambda: unsure(local_img_path)
)
BTN_P_UNSURE.grid(row=1,column=2)
ROOT.mainloop()
return
def unsure(local2_img_path):
global BTN_P_BAD
global BTN_P_GOOD
global BTN_P_UNSURE
global counter
global classification_list
global img_label
global img_name
global PPP
global ROOT
global UNSURE_IMG_PATH
img_name = PPP.iat[counter,0]
if counter == 0:
img_2_save = Pimage.open(first_img_path)
image_save_string = os.path.join(
UNSURE_IMG_PATH,
str('2_'+first_img_path[-19:])
)
else:
# ROOT.title('Image Classification for: '+img_name)
current_img_path = os.path.join(local2_img_path, img_name)
img_2_save = Pimage.open(current_img_path)
image_save_string = os.path.join(
UNSURE_IMG_PATH,
str('2_'+current_img_path[-19:])
)
img_2_save.save(image_save_string)
counter +=1
img_label.grid_forget()
img_name = PPP.iat[counter,0]
str_counter = str(counter)
ROOT.title(
'Image Classification for: '+img_name+ ' Counter: '+str_counter+ 'of 1008'
)
next_img_path=os.path.join(local2_img_path, img_name)
next_imgtk = img_manipulation(next_img_path)
img_label = tk.Label(image = next_imgtk)
img_label.grid(row=0, column=0, columnspan=4)
classification_list.append(2)
BTN_P_GOOD = tk.Button(
ROOT,
text="good or '->'",
fg='green',
font='bold',
justify="center",
activebackground='green',
command=lambda: good(local_img_path)
)
BTN_P_GOOD.grid(row=1,column=3)
BTN_P_BAD = tk.Button(
ROOT,
text="bad or '<-'",
fg='red',
font ='bold',
justify="center",
activebackground='red',
command=lambda: bad(local_img_path)
)
BTN_P_BAD.grid(row=1,column=1)
BTN_P_UNSURE = tk.Button(
ROOT,
text="unsure",
fg='gray',
font ='bold',
justify="center",
activebackground='orange',
command=lambda: unsure(local_img_path)
)
BTN_P_UNSURE.grid(row=1,column=2)
ROOT.mainloop()
return
BTN_P_GOOD = tk.Button(
ROOT,
text="good or '->'",
fg='green',
font='bold',
justify="center",
activebackground='green',
command=lambda: good(local_img_path)
)
BTN_P_BAD = tk.Button(
ROOT,
text="bad or '<-'",
fg='red',
font ='bold',
justify="center",
activebackground='red',
command=lambda: bad(local_img_path)
)
BTN_P_UNSURE = tk.Button(
ROOT,
text="unsure",
fg='gray',
font ='bold',
justify="center",
activebackground='orange',
command=lambda: unsure(local_img_path)
)
BTN_P_QUIT = tk.Button(
ROOT,
text="QUIT",
fg='red',
font ='bold',
justify="center",
activebackground='red',
command = lambda: ROOT.destroy()
)
BTN_P_BAD.grid(row=1,column=1)
BTN_P_GOOD.grid(row=1,column=3)
BTN_P_UNSURE.grid(row=1,column=2)
BTN_P_QUIT.grid(row=1,column=4)
print('\n *** Mainloop start *** \n')
# ROOT.after(2000, lambda: ROOT.destroy())
ROOT.mainloop()
print(
'************************************************* \n' +
'*** Please classify the Pictures in the GUI. ***' +
'\n *************************************************')
try:
os.mkdir(CLASSIFIED_IMG_PATH)
os.mkdir(GOOD_IMG_PATH)
os.mkdir(BAD_IMG_PATH)
os.mkdir(UNSURE_IMG_PATH)
print(
'*** Folder classified images created in:\n',
CLASSIFIED_IMG_PATH,
' ***'
)
except OSError:
pass
if counter == 0:
init_ui(ROOT_PICTURE_PATH_1)
print('First batch samples classified.')
elif counter == 252:
init_ui(ROOT_PICTURE_PATH_1)
print('Second batch samples classified.')
elif counter == 504:
init_ui(ROOT_PICTURE_PATH_1)
print('Third batch samples classified.')
elif counter == 756:
init_ui(ROOT_PICTURE_PATH_1)
print('\n *** Classification completed. ***')
所以你的问题的根本原因是你 re-entrantly 调用 mainloop
,这是一个 no-no.
总而言之,您的代码确实需要大量清理才能正常工作;因为我没有你的本地数据集,也不能完全推断出它在磁盘上的真实结构,这可能不是你想要的,但它应该能让你更接近。
我们的想法是,您构建基础 UI 一次,然后在浏览图像时重新配置它。
import shutil
import sys
import cv2 as cv
import tkinter as tk
import os
import pandas as pd
from PIL import Image, ImageTk
# change the 'init_path' to the location where you unpacked this project
INIT_PATH = "/media/sf_shared_folder/04_coding/99_pipeline"
ROOT_IMG_PATH = os.path.join(INIT_PATH, "03_sorted_data")
CLASSIFIED_IMG_PATH = os.path.join(ROOT_IMG_PATH, "classified_images")
def img_manipulation(local_image_to_manipulate):
img = cv.imread(local_image_to_manipulate)
imgray = cv.cvtColor(img, cv.COLOR_BGR2GRAY)
ret, thresh = cv.threshold(imgray, 127, 255, 0)
contours, hierarchy = cv.findContours(thresh, cv.RETR_TREE, cv.CHAIN_APPROX_SIMPLE)
cv.drawContours(img, [contours[0]], 0, (0, 255, 0), 1)
img = cv.resize(img, (650, 650))
img = Image.fromarray(img)
return ImageTk.PhotoImage(image=img)
class ImageClassificationApp:
def __init__(self, root, image_paths):
self.root = root
self.image_paths = list(image_paths)
self.current_image_index = 0
self.build_ui()
self.update_image()
def build_ui(self):
good_button = tk.Button(
self.root,
text="good or '->'",
fg="green",
font="bold",
justify="center",
activebackground="green",
command=lambda: self.mark_current("good"),
)
good_button.grid(row=1, column=3)
bad_button = tk.Button(
self.root,
text="bad or '<-'",
fg="red",
font="bold",
justify="center",
activebackground="red",
command=lambda: self.mark_current("bad"),
)
bad_button.grid(row=1, column=1)
unsure_button = tk.Button(
self.root,
text="unsure",
fg="gray",
font="bold",
justify="center",
activebackground="orange",
command=lambda: self.mark_current("unsure"),
)
unsure_button.grid(row=1, column=2)
quit_button = tk.Button(
self.root,
text="QUIT",
fg="red",
font="bold",
justify="center",
activebackground="red",
command=lambda: sys.exit(),
)
quit_button.grid(row=1, column=4)
img_label = tk.Label()
img_label.grid(row=0, column=0, columnspan=4)
self.img_label = img_label
@property
def current_image(self):
if self.current_image_index < len(self.image_paths):
return self.image_paths[self.current_image_index]
return None
def update_image(self):
img_name = self.current_image
if not img_name:
return # TODO: handle running out of images more gracefully
self.root.title(
f"Image Classification for: {img_name} Counter: {self.current_image_index} of {len(self.image_paths)} "
)
img_path = os.path.join(ROOT_IMG_PATH, img_name)
image = img_manipulation(img_path)
self.img_label.configure(image=image)
def mark_current(self, mark):
img_name = self.current_image
if not img_name:
return # TODO: handle running out of images more gracefully
dest_dir = os.path.join(CLASSIFIED_IMG_PATH, mark)
os.makedirs(dest_dir, exist_ok=True)
dest_path = os.path.join(dest_dir, img_name)
shutil.copy(os.path.join(ROOT_IMG_PATH, img_name), dest_path)
self.go_to_next_image()
def go_to_next_image(self):
self.current_image_index += 1
self.update_image()
def main():
data = pd.read_csv(os.path.join(ROOT_IMG_PATH, "main_raw_data.csv"))
paths = list(data["PostProcessPicturePath"].values)
root = tk.Tk()
app = ImageClassificationApp(root, paths)
root.mainloop()
if __name__ == "__main__":
main()