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

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

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

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

Tkinter

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

Python

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

Q&A

解決済

1回答

664閲覧

openCVとtkinterをつかったwebカメラからの画像取得、保存プログラムでプログラムの終了ができません

mckie

総合スコア2

OpenCV

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

Tkinter

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

Python

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

0グッド

0クリップ

投稿2023/02/19 09:33

実現したいこと

ここに実現したいことを箇条書きで書いてください。

  • 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/ツールのバージョンなど)

ここにより詳細な情報を記載してください。

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

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

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

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

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

guest

回答1

0

ベストアンサー

get_queue() ==> self.snapshot() ==> self.close() ==> self.thread.join()
の順番に関数が呼び出されています。
self.thread.join()は自分自身のスレッドの終了を待とうとしているのでRuntimeErrorが発生します。

self.snapshot()関数で呼び出しているself.close()を削除すればエラーは出なくなるはずです。

投稿2023/02/19 20:50

TaroToyotomi

総合スコア1430

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

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

mckie

2023/02/19 22:12

snapshotでcloseのメソッドを呼び出したい場合はどうすればよいでしょうか? 宜しくお願いします。
TaroToyotomi

2023/02/20 12:34

pushed_button()メソッドでclose()メソッドを呼べばいいと思いますよ。
mckie

2023/02/23 03:36

ありがとうございます。試してみます
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問