Q&A
実現したいこと
ここに実現したいことを箇条書きで書いてください。
- snapshotボタンを押すと、画像の保存とプログラム自体の終了をしたい。
前提
pythonでwebカメラ画像をopenCVとTKinterでウィンドウに表示しています。
ウィンドウ上にあるsnapshotボタンを押すと、任意のディレクトリに保存されます。
保存を終えるとプログラムの終了をしたいので、画像を保存するメソッドから
プログラムを終了するメソッドを呼び出していますが、エラーが出てしまいます。
ネット上のプログラムを拾って改造している為、中でなにが起こっているか把握できておりません。
初歩的な質問になってしまうと思いますが、ご教授ください。よろしくお願いいたします。
発生している問題・エラーメッセージ
Exception in thread Thread-1 (get_queue): Traceback (most recent call last): File "C:\Program Files\WindowsApps\PythonSoftwareFoundation.Python.3.11_3.11.752.0_x64__qbz5n2kfra8p0\Lib\threading.py", line 1038, in _bootstrap_inner self.run() File "C:\Program Files\WindowsApps\PythonSoftwareFoundation.Python.3.11_3.11.752.0_x64__qbz5n2kfra8p0\Lib\threading.py", line 975, in run self._target(*self._args, **self._kwargs) File "c:\Users\gmasa\OneDrive\ドキュメント\pythonHello\template\test4add__.py", line 132, in get_queue self.snapshot() File "c:\Users\gmasa\OneDrive\ドキュメント\pythonHello\template\test4add__.py", line 149, in snapshot self.close() File "c:\Users\gmasa\OneDrive\ドキュメント\pythonHello\template\test4add__.py", line 46, in close self.thread.join() File "C:\Program Files\WindowsApps\PythonSoftwareFoundation.Python.3.11_3.11.752.0_x64__qbz5n2kfra8p0\Lib\threading.py", line 1109, in join raise RuntimeError("cannot join current thread") RuntimeError: cannot join current thread
該当のソースコード
python
1from datetime import datetime 2from PIL import Image, ImageTk 3from pyzbar.pyzbar import decode 4import cv2 5import queue 6import threading 7import tkinter as tk 8import time 9 10 11class App: 12 def __init__(self, win): 13 video_source = 0 14 self.vcap = cv2.VideoCapture(video_source, cv2.CAP_DSHOW) 15 self.width = self.vcap.get(cv2.CAP_PROP_FRAME_WIDTH) 16 self.height = self.vcap.get(cv2.CAP_PROP_FRAME_HEIGHT) 17 self.font = cv2.FONT_HERSHEY_SIMPLEX 18 19 self.data_queue = queue.Queue() 20 21 self.win = win 22 self.win.title("Camera") 23 self.thread = threading.Thread(target=self.get_queue) 24 self.thread.start() 25 self.disp_center(self.win, 720, 480) 26 #self.win.protocol(self.snapshot,self.close) 27 self.win.protocol("WM_DELETE_WINDOW", self.close) 28 self.create_view() 29 self.bind_event() 30 #self.update_by_timer() 31 self.canvas.after(15, self.update_by_timer) 32 33 34 35 def disp_center(self, win, wx=400, wy=300): 36 #win.resizable(0, 0) 37 dx = win.winfo_screenwidth() 38 dy = win.winfo_screenheight() 39 win_size = str(wx) + "x" + str(wy) + \ 40 "+" + str(int(dx/2 - wx/2)) + "+" + str(int(dy/2 - wy/2)) 41 win.geometry(win_size) 42 43 44 def close(self): 45 self.data_queue.put(["close", None]) 46 self.thread.join() 47 self.win.destroy() 48 self.vcap.release() 49 cv2.destroyAllWindows() 50 51 52 53 54 55 def create_view(self): 56 self.win.rowconfigure(0, weight=1) 57 self.win.columnconfigure(0, weight=1) 58 59 self.frame = tk.Frame(self.win, relief="sunken", bd=1) 60 self.frame.grid(row=0, column=0, sticky="nsew") 61 self.frame.rowconfigure(0, weight=1) 62 self.frame.columnconfigure(0, weight=1) 63 64 self.canvas = tk.Canvas(self.frame) 65 self.canvas.grid(row=0, column=0, sticky="nsew", padx=10, pady=10) 66 67 ret, frm = self.vcap.read() 68 #print("ret: {}".format(ret)) 69 #print("frm: {}".format(frm)) 70 self.frame = cv2.cvtColor(frm, cv2.COLOR_BGR2RGB) 71 self.photo = ImageTk.PhotoImage(image = Image.fromarray(self.frame),master=self.win) 72 #self.canvas.update() 73 cv_w = self.canvas.winfo_reqwidth() 74 cv_h = self.canvas.winfo_reqheight() 75 self.img_id = self.canvas.create_image(cv_w // 2, cv_h // 2, image=self.photo, anchor="center") 76 77 78 """ 79 self.canvas.update() 80 cv_w = self.canvas.winfo_width() 81 cv_h = self.canvas.winfo_height() 82 83 rec_id = self.canvas.create_rectangle(0, 0, cv_w, cv_h, fill="black") 84 85 86 # 長方形の座標取得 87 rec_pos = self.canvas.coords(rec_id) 88 # テキストを描画(位置は適当) 89 text_id = self.canvas.create_text(0, 0, text="NO SIGNAL", font=("", 20), fill="white") 90 # テキストのサイズ取得 91 text_size = self.canvas.bbox(text_id) 92 # テキストの座標移動 93 rc_x = rec_pos[2] / 2 94 rc_y = rec_pos[2] / 3 95 tc_y = text_size[3] / 2 96 self.canvas.move(text_id, rc_x - (rec_pos[0] / 2), rc_y - tc_y) 97 """ 98 99 self.button = tk.Button(self.win, text="Snapshot", command=self.pushed_button) 100 self.button.grid(row=1, column=0, sticky="", pady=10) 101 102 103 def pushed_button(self): 104 self.data_queue.put(["snapshot", None]) 105 106 107 def update_by_timer(self): 108 ret, frm = self.vcap.read() 109 #print("ret: {}".format(ret)) 110 #print("frm: {}".format(frm)) 111 self.frame = cv2.cvtColor(frm, cv2.COLOR_BGR2RGB) 112 self.photo = ImageTk.PhotoImage(image = Image.fromarray(self.frame),master=self.win) 113 self.canvas.itemconfig(self.img_id, image=self.photo) 114 self.canvas.after(15, self.update_by_timer) 115 116 117 def update_by_resize(self, e): 118 self.canvas.itemconfig(self.img_id, image=self.photo, anchor="center") 119 cv_w = self.canvas.winfo_width() 120 cv_h = self.canvas.winfo_height() 121 self.canvas.coords(self.img_id, cv_w // 2, cv_h // 2) 122 123 124 def bind_event(self): 125 self.canvas.bind("<Configure>", self.update_by_resize) 126 127 128 def get_queue(self): 129 while True: 130 msg, data = self.data_queue.get() 131 if msg == "snapshot": 132 self.snapshot() 133 time.sleep(3) 134 break 135 elif msg == "close": 136 break 137 else: 138 print("----- msg error -----") 139 break 140 141 def snapshot(self): 142 filename = "C:/Users/gmasa/OneDrive/" + "L53H" + ".jpg" 143 cv2.imwrite( filename, 144 cv2.cvtColor( self.frame, cv2.COLOR_BGR2RGB ) ) 145 print(filename) 146 #self.data_queue.put(["close", None]) 147 time.sleep(1.5) 148 #self.close() 149 self.close() 150 151 152 153 154 155 156 157 158 159 def mach(self): 160 # 検索対象画像とテンプレート画像の読み込み 161 img = cv2.imread("C:/Users/gmasa/OneDrive/L53H.jpg") 162 template = cv2.imread('C:/Users/gmasa/Videos/input.jpg') 163 164 # テンプレート画像の幅と高さを取得 165 w, h, _ = template.shape 166 167 # 画像の検索(Template Matching) 168 result = cv2.matchTemplate(img, template, cv2.TM_CCORR_NORMED) 169 # 検索結果の信頼度と位置座標の取得 170 min_val, max_val, min_loc, max_loc = cv2.minMaxLoc(result) 171 172 173 # 検索結果の左上頂点の座標を取得 174 top_left = max_loc 175 176 # 検索結果の右下頂点の座標を取得 177 bottom_right = (top_left[0] + w, top_left[1] + h) 178 179 # 検索対象画像内に、検索結果を長方形で描画 180 cv2.rectangle(img, top_left, bottom_right, (255, 255, 0), 2) 181 182 # 画像を表示 183 cv2.imshow('img', img) 184 cv2.imwrite("C:/Users/gmasa/Videos/match3.jpg", img) 185 cv2.waitKey(1) 186 187 188def main(): 189 win = tk.Tk() 190 App(win) 191 win.mainloop() 192 193 194 195if __name__ == "__main__": 196 main()
試したこと
1.queueにcloseのスレッドが立っていないからかと思い、下記をsnapshotメソッドの中に追記しましたが、ダメでした。
self.data_queue.put(["close", None])
2.コンストラクタにある
self.win.protocol("WM_DELETE_WINDOW", self.close)
というコードを真似て
self.win.protocol("WM_DELETE_WINDOW", self.snapshot)
としましたがダメでした。
補足情報(FW/ツールのバージョンなど)
ここにより詳細な情報を記載してください。
回答1件
あなたの回答
tips
プレビュー
下記のような回答は推奨されていません。
このような回答には修正を依頼しましょう。
2023/02/19 22:12
2023/02/20 12:34
2023/02/23 03:36