tkinterでmainloopは記述しているが、ウィンドウが一瞬で消えてしまう
解決したいこと
tkinterを使い、画像と文字をウィンドウに表示させようとしていますが、下記のエラーが出てしまい、画面が一瞬で消えてしまいます。mainloop()は使っているので一瞬で消える原因がわかりません。
プログラムの詳細
openCVを使って、カメラ画像を取得し、その画像から色検出、物体検出をするプログラムを
作っています。
snapshotを撮影すると、webカメラのウィンドウは消えてsnapnumに1が入り、色検出、物体検出して、画像と"OK","NG"判断のウィンドウを表示させます。
一回目のスナップショットのウィンドウは正しく表示され、正しく終了できますが
二回目のウィンドウ(色検出、物体検出後のOK、NG表示)が一瞬で消えてしまいます。
mainloopは使っていますが、表示できません。
エラーを調べると、disp_imageが定義されていないときに呼ばれているとの事らしいですが、解決方法がわかりませんでした。どなたかわかる方がいらしたらご教授お願いします。
発生している問題・エラー
invalid command name "2343488254208disp_image"
while executing
"2343488254208disp_image"
("after" script)
#"disp_image"の前の数字はプログラムを動かす度に変化します。
該当するソースコード
import tkinter as tk
from tkinter import filedialog
from PIL import Image, ImageTk, ImageOps # 画像データ用
import matplotlib.pyplot as plt
from matplotlib.patches import Polygon
import numpy as np
from tkinter import font
import time
import cv2
class Application(tk.Frame):
def __init__(self, master = None):
super().__init__(master)
self.pack()
fonts = ("", 14)
self.master.title("OpenCVの動画表示") # ウィンドウタイトル
self.master.geometry("1000x500") # ウィンドウサイズ(幅x高さ)
frame1 = tk.Frame(self.master, width=400,height=800)
frame1.pack(expand = True,fill=tk.BOTH)
self.button = tk.Button(frame1,text="Snapshot",width=20, height=5, font=fonts,bg="beige" ,command=self.snapshot)
self.button.pack(side=tk.BOTTOM,fill=tk.X)
# Canvasの作成
self.canvas = tk.Canvas(frame1)
# Canvasにマウスイベント(左ボタンクリック)の追加
self.canvas.bind('<Button-1>', self.canvas_click)
# Canvasを配置
self.canvas.pack(expand = True, fill = tk.BOTH)
# カメラをオープンする
self.capture = cv2.VideoCapture(0)
self.disp_id = None
def canvas_click(self, event):
'''Canvasのマウスクリックイベント'''
if self.disp_id is None:
# 動画を表示
self.disp_image()
else:
# 動画を停止
self.after_cancel(self.disp_id)
self.disp_id = None
def disp_image(self):
'''画像をCanvasに表示する'''
# フレーム画像の取得
ret, self.frame22 = self.capture.read()
# BGR→RGB変換
cv_image = cv2.cvtColor(self.frame22, cv2.COLOR_BGR2RGB)
# NumPyのndarrayからPillowのImageへ変換
pil_image = Image.fromarray(cv_image)
# キャンバスのサイズを取得
canvas_width = self.canvas.winfo_width()
canvas_height = self.canvas.winfo_height()
# 画像のアスペクト比(縦横比)を崩さずに指定したサイズ(キャンバスのサイズ)全体に画像をリサイズする
pil_image = ImageOps.pad(pil_image, (canvas_width, canvas_height))
# PIL.ImageからPhotoImageへ変換する
self.photo_image = ImageTk.PhotoImage(image=pil_image)
# 画像の描画
self.canvas.create_image(
canvas_width / 2, # 画像表示位置(Canvasの中心)
canvas_height / 2,
image=self.photo_image # 表示画像データ
)
# disp_image()を10msec後に実行する
self.disp_id = self.after(10, self.disp_image)
def snapshot(self):
filename = "C:/Users/Pictures/match.png"
self.snapnum = 1
cv2.imwrite( filename,self.frame22)
print(filename)
self.master.destroy()
self.capture.release()
#time.sleep(5)
#match_suc:match_suc
cv2.destroyAllWindows()
time.sleep(5)
self.snapnum = 1
if __name__ == "__main__":
root = tk.Tk()
app = Application(master = root)
app.mainloop()
if app.snapnum == 1:
window = tk.Tk()
img = cv2.imread("C:/Users/Pictures/match.png") # 画像を読み込む。
# 色基準で2値化する。
hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV) # HSV 色空間に変換
red = cv2.inRange(hsv, np.array([145, 70, 0]), np.array([180, 255, 255]))
yellow = cv2.inRange(hsv, np.array([10, 80, 0]), np.array([50, 255, 255]))
green = cv2.inRange(hsv, np.array([30, 190, 0]), np.array([90, 255, 255]))
blue = cv2.inRange(hsv, np.array([90, 70, 90]), np.array([210, 255, 255]))
#white = cv2.inRange(hsv, np.array([108, 21, 0]), np.array([255, 70, 255]))
# 白だけゴミがあるので、収縮演算
kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (3, 3))
#white = cv2.erode(white, kernel)
bin_imgs = {'red': red, 'yellow': yellow, 'green': green,
'blue': blue, }
fig, ax = plt.subplots(figsize=(8, 5))
ax.axis('off')
ax.imshow(cv2.cvtColor(img, cv2.COLOR_BGR2RGB))
count1 = {'red':0,'yellow':0,'green':0,'blue':0}
# 輪郭検出し、数を求める。
##############################################
for label, bin_img in bin_imgs.items():
contours,hierarchy = cv2.findContours(
bin_img, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
# 輪郭を構成する頂点数で誤検出を除く。
contours = list(filter(lambda cnt: len(cnt) > 30, contours))
count = len(contours)
count1[label] = count
print('color: {}, conunt: {}'.format(label, count))
# 描画する。
for cnt in contours:
cnt = np.squeeze(cnt, axis=1) # (N, 1, 2) -> (N, 2)
ax.add_patch(Polygon(cnt, fill=None, lw=2., color=label))
plt.savefig("C:/Users/Pictures/matchafter.png")
#plt.show()
fonts = ("", 14)
window.title("処理結果") # ウィンドウタイトル
window.geometry("1200x700") # ウィンドウサイズ(幅x高さ)
frame1 = tk.Frame(window,bg="beige",width=1200,height=500)
frame1.pack(expand = True,fill=tk.BOTH)
# Canvasの作成
canvas = tk.Canvas(frame1,bg="beige",width=1200,height=500)
# Canvasを配置
canvas.pack(expand = True, fill = tk.BOTH)
#\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\
# フレーム画像の取得
img = ImageTk.PhotoImage(file = "C:/Users/Pictures/matchafter.png")
w = img.width # 横幅を取得
h = img.height # 縦幅を取得
#img = img.resize(( int(w * (800/w)), int(h * (800/w)) ))
# キャンバスのサイズを取得
canvas_width = canvas.winfo_width()
canvas_height = canvas.winfo_height()
RedAnswer = 5
BlueAnswer = 5
YellowAnswer = 5
GreenAnswer = 5
if (count1['red']) >= RedAnswer and \
(count1['yellow']) >= YellowAnswer and\
(count1['green']) >= GreenAnswer and \
(count1['blue']) >= BlueAnswer :
font1 = font.Font(family='Helvetica', size=110, weight='bold')
label2 = tk.Label(window, text="OK",font=font1,fg="green") #文字ラベル設定
label2.pack(side = "bottom")
canvas.create_image(
600, # 画像表示位置(Canvasの中心)
250,
image=img,
anchor = tk.CENTER
# 表示画像データ
)
else:
rednotenough = RedAnswer-(count1['red'])
yellowNotEnough = YellowAnswer-(count1['yellow'])
greenNotEnough = GreenAnswer-(count1['green'])
blueNotEnough = BlueAnswer-(count1['blue'])
#0以下は0にする
rednotenough = max(0,rednotenough)
yellowNotEnough = max(0,yellowNotEnough)
greenNotEnough = max(0,greenNotEnough)
blueNotEnough = max(0,blueNotEnough)
font0 = font.Font(family='Helvetica', size=20, weight='bold')
text0 = "赤色が"+ str(rednotenough) + "個\n"\
"黄色が"+ str(yellowNotEnough) + "個\n"\
"緑が"+ str(greenNotEnough) + "個\n"\
"青が"+ str(blueNotEnough) + "個\n"\
"足りません"
label0 = tk.Label(window, text=text0,font=font0,fg="red")
label0 .place(relx=0.85,rely=0.75)
font1 = font.Font(family='Helvetica', size=110, weight='bold')
label1 = tk.Label(window, text="NG",font=font1,fg="red") #文字ラベル設定
label1.pack(side = "bottom")
canvas.create_image(
600, # 画像表示位置(Canvasの中心)
250,
image=img,
anchor = tk.CENTER
# 表示画像データ
)
window.mainloop()
自分で試したこと
2回目のウィンドウ表示である、window.mainloopをifの外や中に移動してみましたが変わりませんでした
0