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

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

新規登録して質問してみよう
ただいま回答率
85.35%
Windows 10

Windows 10は、マイクロソフト社がリリースしたOSです。Modern UIを標準画面にした8.1から、10では再びデスクトップ主体に戻され、UIも変更されています。PCやスマホ、タブレットなど様々なデバイスに幅広く対応していることが特徴です。

ウィンドウ

コンピューター用語において、ウィンドウとはユーザとプログラムのやり取りを可能にするGUIの枠組みのことをいいます。

Python

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

PyCharm

エディター・開発ツール

Q&A

解決済

1回答

2675閲覧

撮影ウィンドウが閉じれず処理が終わらない

_N_M_

総合スコア1

Windows 10

Windows 10は、マイクロソフト社がリリースしたOSです。Modern UIを標準画面にした8.1から、10では再びデスクトップ主体に戻され、UIも変更されています。PCやスマホ、タブレットなど様々なデバイスに幅広く対応していることが特徴です。

ウィンドウ

コンピューター用語において、ウィンドウとはユーザとプログラムのやり取りを可能にするGUIの枠組みのことをいいます。

Python

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

PyCharm

エディター・開発ツール

0グッド

0クリップ

投稿2020/12/18 01:55

前提・実現したいこと

撮影した画像の顔認識を実行するphoto.pyを起動させるGUIを開発しています。

python

1# GUI_test.py 2import PySimpleGUI as sg 3 4# ウィンドウに配置するコンポーネント 5layout = [ [sg.Text('撮影しますか?')], 6 [sg.Button('OK'), sg.Button('キャンセル')] ] 7 8# ウィンドウの生成 9window = sg.Window('サンプルプログラム', layout) 10 11# イベントループ 12while True: 13 event, values = window.read() 14 if event == sg.WIN_CLOSED or event == 'キャンセル': 15 break 16 elif event == 'OK': 17 window.close() 18 import photo 19 print("撮影完了") 20 21window.close()

python

1# photo.py 2import cv2 3import os 4import matplotlib.pyplot as plt 5 6def save_frame_camera_key(device_num, dir_path, basename, ext='jpg', delay=1, window_name='frame'): 7 cap = cv2.VideoCapture(device_num) 8 9 if not cap.isOpened(): 10 return 11 12 os.makedirs(dir_path, exist_ok=True) 13 14 # cで撮影、qで認識して終了 15 n = 0 16 while True: 17 ret, frame = cap.read() 18 cv2.imshow(window_name, frame) 19 key = cv2.waitKey(delay) & 0xFF 20 if key == ord('c'): 21 cv2.imwrite("face.jpg", frame) 22 n += 1 23 elif key == ord('q'): 24 # カスケードファイルを使って認識器を作成 25 cascade_file = "haarcascade_frontalface_alt.xml" 26 cascade = cv2.CascadeClassifier(cascade_file) 27 28 # 画像を読み込みグレイスケールに変換 29 img = cv2.imread("face.jpg") 30 gray_cv = cv2.cvtColor(img, cv2.COLOR_RGB2GRAY) 31 32 # 顔認識 33 face_list = cascade.detectMultiScale(gray_cv, minSize=(150, 150)) 34 # 認識失敗時の処理 35 if len(face_list) == 0: 36 print("失敗") 37 continue 38 39 # 認識した顔の座標、位置を視覚化 40 for (x, y, w, h) in face_list: 41 print("顔の座標(x,y,w,h):", x, y, w, h) 42 red = (0, 0, 255) 43 cv2.rectangle(img, (x, y), (x + w, y + h), red, thickness=20) 44 45 # 顔認識した画像を表示 46 cv2.imwrite("face-recognition.jpg", img) 47 plt.imshow(cv2.cvtColor(img, cv2.COLOR_BGR2RGB)) 48 plt.show() 49 break 50 51 cv2.destroyWindow(window_name) 52 53save_frame_camera_key(0, 'data/temp', 'camera_capture')

発生している問題

photo.py単体では問題なくプログラムが終了しましたが、GUIから起動すると撮影ウィンドウが残り処理が終了しませんでした。
アドバイスを頂けると幸いです。よろしくお願いします。

試したこと

photo.pyの「cv2.destroyWindow(window_name)」を「cv2.destroyAllWindows()」と変更してみましたが、変化はありませんでした。
また、手動での操作を試したところウィンドウは閉じましたが、処理は終わらないままでした。

補足情報

OS:Windows10
Pythonのバージョン:Python3.8.5
開発環境:PyCharm Community Edition 2020.2.4 x64

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

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

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

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

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

guest

回答1

0

ベストアンサー

問題点: イベントループの競合
cv2.waitKey で PySimpleGUI のイベントループが止まってしまいます。

  • photo.py の while True: ループを抜ける条件は、'q' キーが入力された時
  • GUI_test.py の while True: ループの終了条件は、キャンセルボタンかウィンドウが閉じられた時。

ですが、単一スレッド上で動作してるため、
photo.py 側のループ中は GUI_test.py のイベントは処理されませんし、
GUI_test.py の event.read() でキー入力を補足しても、photo.py 側の waitkey には影響しません。

pyplot と PySimpleGUI のバックエンドが tkinter だった場合も、
tkinter の初期化処理が競合してしまうので、この場合は「別プロセス」にしたほうが良いです。

解決策:
キー入力等は PySimpleGUI 側に任せて、外部プロセスのカメラを操作する。
「プロセス間通信」などの知識が必要になってきます。

※ 別プロセスにしたくない場合は、画像表示に pyplot を使わずに
PySimpleGUI 側で行う方法を検討してください。pyplot を省ければ、
「プロセス」の代わりに「スレッド」を使う選択肢もあります。

「cv2.destroyWindow(window_name)」を「cv2.destroyAllWindows()」と変更してみましたが、変化はありませんでした。

cv2 の管理するウィンドウとPySimpleGUI のウィンドウは別です。

追記:
GUI は、撮影するかどうかの確認のみですが
他に GUI に機能を追加する予定はありますか?

なければ、プログラムの構造をシンプルにする方法も考えられます。
GUI_test.py の処理を、OK ボタンを押した時 True を返す関数として実装することで

if 撮影しますか? : # <-- ここで PySimpleGUI の利用は完全に終わる (while True: ループは抜ける) 撮影処理 # photo.py cv2/pyplot を使う

イベントループを分離できるので、終了できない問題を解消できるはずです。


他の問題点、質問には直接関係ない部分ですが、Pythonのモジュールについて

import photo だけでは、モジュールがキャッシュされてる場合
コードが実行されない場合があります。

python

1# photo.py 側の変更 2 3if __name__ == "__main__": 4 save_frame_camera_key(0, 'data/temp', 'camera_capture')

python

1# GUI_test.py 側の変更 (適切なインデントで) 2 3import photo 4photo.save_frame_camera_key(0, 'data/temp', 'camera_capture')

投稿2020/12/18 02:50

編集2020/12/18 03:13
teamikl

総合スコア8760

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

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

_N_M_

2020/12/30 05:46

返信が遅くなり申し訳ありません。 この度はご回答いただきありがとうございました。 提示して頂いた解決策の通りキー入力をGUI側で実行するようにしたところ、無事に問題を解決することができました。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.35%

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

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

質問する

関連した質問