質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
Visual Studio Code

Visual Studio Codeとは、Microsoft社が開発したマルチプラットフォーム対応のテキストエディタです。Visual Studioファミリーの一員でもあります。拡張性とカスタマイズ性が高く、テキストエディタでありながら、IDEと遜色ない機能を備えることができます。

OpenCV

OpenCV(オープンソースコンピュータービジョン)は、1999年にインテルが開発・公開したオープンソースのコンピュータビジョン向けのクロスプラットフォームライブラリです。

Tkinter

Tkinterは、GUIツールキットである“Tk”をPythonから利用できるようにした標準ライブラリである。

Python

Pythonは、コードの読みやすさが特徴的なプログラミング言語の1つです。 強い型付け、動的型付けに対応しており、後方互換性がないバージョン2系とバージョン3系が使用されています。 商用製品の開発にも無料で使用でき、OSだけでなく仮想環境にも対応。Unicodeによる文字列操作をサポートしているため、日本語処理も標準で可能です。

Q&A

0回答

552閲覧

別ファイルのTKinterのウィンドウmainloop()が抜け出せない

mckie

総合スコア2

Visual Studio Code

Visual Studio Codeとは、Microsoft社が開発したマルチプラットフォーム対応のテキストエディタです。Visual Studioファミリーの一員でもあります。拡張性とカスタマイズ性が高く、テキストエディタでありながら、IDEと遜色ない機能を備えることができます。

OpenCV

OpenCV(オープンソースコンピュータービジョン)は、1999年にインテルが開発・公開したオープンソースのコンピュータビジョン向けのクロスプラットフォームライブラリです。

Tkinter

Tkinterは、GUIツールキットである“Tk”をPythonから利用できるようにした標準ライブラリである。

Python

Pythonは、コードの読みやすさが特徴的なプログラミング言語の1つです。 強い型付け、動的型付けに対応しており、後方互換性がないバージョン2系とバージョン3系が使用されています。 商用製品の開発にも無料で使用でき、OSだけでなく仮想環境にも対応。Unicodeによる文字列操作をサポートしているため、日本語処理も標準で可能です。

0グッド

0クリップ

投稿2023/03/02 03:24

実現したいこと

main.pyのGUIボタンから別ファイルのcolorMatch.pyを実行したいです。

main.pyから色判断をするプログラムcolorMatch.pyをGUIのボタンで呼び出しています。
colorMatch.pyの構成は

①cv2で画像を取得し、canvasにリアルタイム表示するクラス Application
②取得した画像を画像処理をして結果を出すクラス match

になっています。
colorMatch.pyは単体で実行すると思った通りの動きをしますが、
別ファイルのGUIのボタンで呼び出すと、①のmainloop()が抜けられず、②クラスに行けません。

ですが、main.pyのGUI画面を閉じるとmainloop()を抜けて②が実行されます。
main.pyの画面を閉じないでmainloop()を抜けたいです。

発生している問題・エラーメッセージ

エラーメッセージは出ていません

該当のソースコード(main.py)

python

1import tkinter as tk 2 3 4class main: 5 def __init__(self) -> None: 6 win = tk.Tk() 7 win.title("main") 8 win.geometry('510x170') 9 Button1= tk.Button(win, text="カラーマッチング",bg="lightgreen",command= self.ctdown).grid() 10 win.mainloop() 11 12 13 14 15 def ctdown(self): 16 import colorMatch 17 18 19 20app = main()

該当のソースコード(colorMatch.py)

python

1import tkinter as tk 2from tkinter import filedialog 3from PIL import Image, ImageTk, ImageOps # 画像データ用 4import matplotlib.pyplot as plt 5from matplotlib.patches import Polygon 6import numpy as np 7from tkinter import font 8import time 9from tkinter import messagebox 10import cv2 11import sys 12 13class Application(tk.Frame): 14 15 def __init__(self, master = None): 16 super().__init__(master) 17 self.pack() 18 19 fonts = ("", 14) 20 21 22 self.master.title("OpenCVの動画表示") # ウィンドウタイトル 23 self.master.geometry("1330x750+0+0") 24 #self.master.attributes('-fullscreen', True) # ウィンドウサイズ(幅x高さ) 25 26 27 28 frame1 = tk.Frame(self.master, width=400,height=800) 29 frame1.pack(expand = True,fill=tk.BOTH) 30 31 32 self.button = tk.Button(frame1,text="Snapshot",width=20, height=5, font=fonts,bg="beige" ,command=self.snapshot) 33 self.button.pack(side=tk.BOTTOM,fill=tk.X) 34 35 # Canvasの作成 36 self.canvas = tk.Canvas(frame1) 37 # Canvasにマウスイベント(左ボタンクリック)の追加 38 self.canvas.bind('<Button-1>', self.canvas_click) 39 # Canvasを配置 40 self.canvas.pack(expand = True, fill = tk.BOTH) 41 42 # カメラをオープンする 43 self.capture = cv2.VideoCapture(0) 44 45 self.disp_id = None 46 47 48 49 50 def canvas_click(self, event): 51 '''Canvasのマウスクリックイベント''' 52 53 if self.disp_id is None: 54 # 動画を表示 55 self.disp_image() 56 else: 57 # 動画を停止 58 self.after_cancel(self.disp_id) 59 self.disp_id = None 60 61 def disp_image(self): 62 '''画像をCanvasに表示する''' 63 64 # フレーム画像の取得 65 ret, self.frame22 = self.capture.read() 66 67 # BGR→RGB変換 68 cv_image = cv2.cvtColor(self.frame22, cv2.COLOR_BGR2RGB) 69 # NumPyのndarrayからPillowのImageへ変換 70 pil_image = Image.fromarray(cv_image) 71 72 # キャンバスのサイズを取得 73 canvas_width = self.canvas.winfo_width() 74 canvas_height = self.canvas.winfo_height() 75 76 # 画像のアスペクト比(縦横比)を崩さずに指定したサイズ(キャンバスのサイズ)全体に画像をリサイズする 77 pil_image = ImageOps.pad(pil_image, (canvas_width, canvas_height)) 78 79 # PIL.ImageからPhotoImageへ変換する 80 self.photo_image = ImageTk.PhotoImage(master = self.master,image=pil_image) 81 82 # 画像の描画 83 self.canvas.create_image( 84 canvas_width / 2, # 画像表示位置(Canvasの中心) 85 canvas_height / 2, 86 image=self.photo_image # 表示画像データ 87 ) 88 89 90 # disp_image()を10msec後に実行する 91 self.disp_id = self.after(10, self.disp_image) 92 93 94 def snapshot(self): 95 filename = "C:/Users/Pictures/test.png" 96 self.snapnum = 1 97 self.after_cancel(self.disp_id) 98 self.disp_id = None 99 100 cv2.imwrite( filename,self.frame22) 101 print(filename) 102 self.master.destroy() 103 self.capture.release() 104 105 cv2.destroyAllWindows() 106 time.sleep(1) 107 self.snapnum = 1 108 109class match(tk.Frame): 110 111 def __init__(self, master = None): 112 super().__init__(master) 113 #self.pack() 114 self.pinCorrect = 0 115 116 117 self.master.title("処理結果") # ウィンドウタイトル 118 self.master.geometry("1330x750+0+0") 119 self.master.lift() 120 121 #root.protocol('WM_DELETE_WINDOW', quit) 122 img = cv2.imread("C:/Users/Pictures/test.png") # 画像を読み込む。 123 124 # 色基準で2値化する。 125 hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV) # HSV 色空間に変換 126 127 red = cv2.inRange(hsv, np.array([145, 70, 0]), np.array([180, 255, 255])) 128 yellow = cv2.inRange(hsv, np.array([10, 80, 0]), np.array([50, 255, 255])) 129 green = cv2.inRange(hsv, np.array([30, 190, 0]), np.array([90, 255, 255])) 130 blue = cv2.inRange(hsv, np.array([90, 70, 90]), np.array([210, 255, 255])) 131 #white = cv2.inRange(hsv, np.array([108, 21, 0]), np.array([255, 70, 255])) 132 133 # 白だけゴミがあるので、収縮演算 134 kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (3, 3)) 135 #white = cv2.erode(white, kernel) 136 137 138 bin_imgs = {'red': red, 'yellow': yellow, 'green': green, 139 'blue': blue, } 140 141 142 143 144 145 146 fig, ax = plt.subplots(figsize=(8, 5)) 147 ax.axis('off') 148 ax.imshow(cv2.cvtColor(img, cv2.COLOR_BGR2RGB)) 149 count1 = {'red':0,'yellow':0,'green':0,'blue':0} 150 # 輪郭検出し、数を求める。 151 ############################################## 152 for label, bin_img in bin_imgs.items(): 153 contours,hierarchy = cv2.findContours( 154 bin_img, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE) 155 # 輪郭を構成する頂点数で誤検出を除く。 156 contours = list(filter(lambda cnt: len(cnt) > 30, contours)) 157 count = len(contours) 158 count1[label] = count 159 print('color: {}, conunt: {}'.format(label, count)) 160 161 # 描画する。 162 for cnt in contours: 163 cnt = np.squeeze(cnt, axis=1) # (N, 1, 2) -> (N, 2) 164 ax.add_patch(Polygon(cnt, fill=None, lw=2., color=label)) 165 plt.show(block=False) 166 plt.savefig("C:/Users/Pictures/testafter.png") 167 168 plt.show(block=False) 169 plt.close() 170 171 172 173 frame1 = tk.Frame(self.master,bg="beige",width=1200,height=500) 174 frame1.pack(expand = True,fill=tk.BOTH) 175 176 177 178 # Canvasの作成 179 canvas = tk.Canvas(frame1,bg="beige",width=1200,height=500) 180 181 # Canvasを配置 182 canvas.pack(expand = True, fill = tk.BOTH) 183#\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\ 184 # フレーム画像の取得 185 img = ImageTk.PhotoImage(master = self.master,file = "C:/Users/Pictures/testafter.png") 186 self.w = img.width # 横幅を取得 187 self.h = img.height # 縦幅を取得 188 189 190 191 # キャンバスのサイズを取得 192 self.canvas_width = canvas.winfo_width() 193 self.canvas_height = canvas.winfo_height() 194 195 196 RedAnswer = 5 197 BlueAnswer = 5 198 YellowAnswer = 5 199 GreenAnswer = 5 200 201 if (count1['red']) >= RedAnswer and \ 202 (count1['yellow']) >= YellowAnswer and\ 203 (count1['green']) >= GreenAnswer and \ 204 (count1['blue']) >= BlueAnswer : 205 self.pinCorrect = 1 206 font1 = font.Font(family='Helvetica', size=110, weight='bold') 207 label2 = tk.Label(self.master, text="OK",font=font1,fg="green") #文字ラベル設定 208 label2.pack(side = "bottom") 209 canvas.create_image( 210 600, # 画像表示位置(Canvasの中心) 211 250, 212 image=img, 213 anchor = tk.CENTER 214 # 表示画像データ 215 ) 216 217 else: 218 rednotenough = RedAnswer-(count1['red']) 219 yellowNotEnough = YellowAnswer-(count1['yellow']) 220 greenNotEnough = GreenAnswer-(count1['green']) 221 blueNotEnough = BlueAnswer-(count1['blue']) 222 self.pinCorrect = 0 223 #0以下は0にする 224 rednotenough = max(0,rednotenough) 225 yellowNotEnough = max(0,yellowNotEnough) 226 greenNotEnough = max(0,greenNotEnough) 227 blueNotEnough = max(0,blueNotEnough) 228 229 font0 = font.Font(family='Helvetica', size=20, weight='bold') 230 text0 = "赤色が"+ str(rednotenough) + "個\n"\ 231 "黄色が"+ str(yellowNotEnough) + "個\n"\ 232 "緑が"+ str(greenNotEnough) + "個\n"\ 233 "青が"+ str(blueNotEnough) + "個\n"\ 234 "足りません" 235 236 237 238 239 240 label0 = tk.Label(self.master, text=text0,font=font0,fg="red") 241 label0 .place(relx=0.85,rely=0.75) 242 243 244 font1 = font.Font(family='Helvetica', size=110, weight='bold') 245 label1 = tk.Label(self.master, text="NG",font=font1,fg="red") #文字ラベル設定 246 label1.pack(side = "bottom") 247 248 canvas.create_image( 249 600, # 画像表示位置(Canvasの中心) 250 250, 251 image=img, 252 anchor = tk.CENTER 253 # 表示画像データ 254 ) 255 256 #time.sleep() 257 ret = messagebox.showerror("NG画面", "マッチしていません") 258 if ret == "ok": 259 self.master.quit() 260 self.master.destroy() 261 262 263while True: 264 root = tk.Tk() 265 app = Application(master = root) 266 app.mainloop() 267 if app.snapnum == 1: 268 win = tk.Tk() 269 apple= match(master = win) 270 apple.mainloop() 271 print("done33") 272 if apple.pinCorrect == 1: 273 break 274 275 276

試したこと

google検索
検索しましたが、同じパターンのページを見つけることができず、解決に至りませんでした。

補足情報(FW/ツールのバージョンなど)

開発環境はVScodeで言語はpython です。
お分かりになる方がいましたらご教授お願いいたします。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

melian

2023/03/02 17:14

snapshot メソッド内で self.master.quit() を実行する必要がある様に思えます。(quit()を実行することでアプリケーションループが終了します) def snapshot(self):   filename = "C:/Users/Pictures/test.png"   self.snapnum = 1   if self.disp_id is not None:     self.after_cancel(self.disp_id)     self.disp_id = None   cv2.imwrite( filename,self.frame22)   print(filename)   self.master.quit() # 追加   self.master.destroy()   self.capture.release()   cv2.destroyAllWindows()   time.sleep(1)
mckie

2023/03/03 00:07

melianさん コメントありがとうございます。 self.master.quit() を追加してやってみたところ、次の画面(matchクラス)へ行くことができました! ですが、colormatchでマッチしなかった場合、一番下の部分のwhile Trueでもう一度カメラ画像取得画面へいく予定ですが、行ってくれません。matchクラスの最後にself.master.quit() を追記してみてもダメでした。これもまた、main.pyのGUI画面を閉じると動きます。 続けての質問になってしまい申し訳ございませんがお分かりでしたら教えてください。
melian

2023/03/03 02:48

match クラスの場合、__init__() で全てを実行していますので、アプリケーションループ(mainloop())は不要かと思います。 if app.snapnum == 1:  win = tk.Tk()  apple= match(master = win)  #apple.mainloop() ## 不要  print("done33")  if apple.pinCorrect == 1:   break
mckie

2023/03/03 03:50

ありがとうございます! mainloopを消したら正常に動作しました!
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

まだ回答がついていません

会員登録して回答してみよう

アカウントをお持ちの方は

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問