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

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

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

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

Python 3.x

Python 3はPythonプログラミング言語の最新バージョンであり、2008年12月3日にリリースされました。

Tkinter

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

Q&A

解決済

3回答

1362閲覧

opencvで異常検知すると、Tkinterにて警告を出したい

biifun5846

総合スコア11

OpenCV

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

Python 3.x

Python 3はPythonプログラミング言語の最新バージョンであり、2008年12月3日にリリースされました。

Tkinter

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

0グッド

0クリップ

投稿2018/08/18 02:49

編集2018/08/20 15:21

前提・実現したいこと

初心者ですので不躾な質問になるかもしれないですが、よろしくお願いします。
pythonにて、OPENCVを利用し、色が閾値を超えるドットの個数がある一定数を超えると、GUIで警告表示をしたい。

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

while文の中にTkinterを組み込むと、動画検知が一旦停止してしまいます。
止まる原理はroot.mainloop()が原因と思われますが、Tkinterの方法としてこれしか調べることが出来ませんでした。

1.検知しながら、独立して警告用ウィンドウを出し続けるにはどうしたらいいのでしょうか?
2.そもそもOPENCVとTkinterを併用するのは間違っているのでしょうか?

よろしくお願いします。

該当のソースコード

python3

1# OpenCV のインポート 2import cv2 3import numpy as np 4import csv 5import tkinter as tk 6 7# VideoCaptureのインスタンスを作成する。 8# 引数でカメラを選べれる。 9cap = cv2.VideoCapture(0) 10 11while True: 12 root = tk.Tk() 13 root.title(u"コンパクター") 14 root.geometry("400x400") 15 16 frame1 = tk.Frame(root, pady=5) 17 frame1.pack() 18 label1 = tk.Label(frame1, font=("", 14), width=40) 19 label1.pack(side="top") 20 21 #root.mainloop() 22 # VideoCaptureから1フレーム読み込む 23 ret, frame = cap.read() 24 25 # スクリーンショットを撮りたい関係で1/4サイズに縮小 26 #frame = cv2.resize(frame, (int(frame.shape[1]/1), int(frame.shape[0]/1))) 27 # 加工なし画像を表示する 28 #cv2.imshow('Raw Frame', frame) 29 30 # 何か処理(ここでは文字列「hogehoge」を表示する) 31 edframe = frame 32 cv2.putText(edframe, 'test', (0, 50), 33 cv2.FONT_HERSHEY_PLAIN, 3, (0, 255, 0), 3, cv2.LINE_AA) 34 cv2.line(edframe, (300, 60), (300, 400), (0, 0, 255)) 35 #cv2.circle(edframe, (100, 100), 15, (255, 255, 255), thickness=-1) 36 cv2.ellipse(edframe, (300, 230), (10, 10), 0, 0, 360, (0, 0, 255)) 37 cv2.ellipse(edframe, (300, 330), (10, 10), 0, 0, 360, (0, 0, 255)) 38 cv2.ellipse(edframe, (300, 120), (10, 10), 0, 0, 360, (0, 0, 255)) 39 px = edframe[230,301] #y,xなので注意 40 px2 = edframe[330,301] 41 px3 = edframe[120,301] 42 #print("{},{},{}".format(px3,px,px2)) 43 44 #print(type(px)) 45 if (px[0] > 100 and px[1] > 100 and px[2] > 100) : 46 #print("検知開始") 47 wide = 0 48 for i in range(50,450): 49 pxpaper = edframe[i,301] 50 if (pxpaper[0] > 130 and pxpaper[1] > 130 and pxpaper[2] > 130): 51 wide += 1 52 cv2.ellipse(edframe, (297, i), (1, 1), 0, 0, 360, (255, 0, 255)) 53 else : 54 pass 55 print(wide)#, end=" ") 56 else : 57 pass 58 # 加工済の画像を表示する 59 cv2.imshow('Edited Frame', edframe) 60 61 # キー入力を1ms待って、k が27(ESC)だったらBreakする 62 k = cv2.waitKey(1) 63 if k == 27: 64 break 65 root.mainloop() 66 67# キャプチャをリリースして、ウィンドウをすべて閉じる 68cap.release() 69cv2.destroyAllWindows()

試したこと

while文の前に入れてみたり、root.mainloop()の位置をwhile文の外に出したりしてみましたが、止まり方が変わるだけで解決しませんでした。

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

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

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

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

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

guest

回答3

0

OPENCVのみ使用して、テキスト専用ウィンドウを作りました
img = np.full((210, 425, 3), 128, dtype=np.uint8)

python3

1# OpenCV のインポート 2import cv2 3import numpy as np 4import csv 5 6# VideoCaptureのインスタンスを作成する。 7# 引数でカメラを選べれる。 8cap = cv2.VideoCapture(0) 9 10#cap.set(cv2.CAP_PROP_FPS, 60) # カメラFPSを60FPSに設定 11cap.set(cv2.CAP_PROP_FRAME_WIDTH, 1280) # カメラ画像の横幅を1280に設定 12cap.set(cv2.CAP_PROP_FRAME_HEIGHT, 720) # カメラ画像の縦幅を720に設定 13 14while True: 15 16 #テキストフレームの作成 17 img = np.full((210, 425, 3), 128, dtype=np.uint8) 18 # VideoCaptureから1フレーム読み込む 19 ret, frame = cap.read() 20 21 # スクリーンショットを撮りたい関係で1/4サイズに縮小 22 #frame = cv2.resize(frame, (int(frame.shape[1]/1), int(frame.shape[0]/1))) 23 # 加工なし画像を表示する 24 #cv2.imshow('Raw Frame', frame) 25 26 # 何か処理(ここでは文字列「hogehoge」を表示する) 27 edframe = frame 28 #cv2.putText(edframe, 'test', (0, 50), 29 # cv2.FONT_HERSHEY_PLAIN, 3, (0, 255, 0), 3, cv2.LINE_AA) 30 cv2.line(edframe, (300, 60), (300, 400), (0, 0, 255)) 31 #cv2.circle(edframe, (100, 100), 15, (255, 255, 255), thickness=-1) 32 cv2.ellipse(edframe, (300, 230), (10, 10), 0, 0, 360, (0, 0, 255)) 33 cv2.ellipse(edframe, (300, 330), (10, 10), 0, 0, 360, (0, 0, 255)) 34 cv2.ellipse(edframe, (300, 120), (10, 10), 0, 0, 360, (0, 0, 255)) 35 px = edframe[230,301] #y,xなので注意 36 px2 = edframe[330,301] 37 px3 = edframe[120,301] 38 #print("{},{},{}".format(px3,px,px2)) 39 40 #print(type(px)) 41 if (px[0] > 100 and px[1] > 100 and px[2] > 100) : 42 cv2.putText(img, 'Detection', (50, 50), 43 cv2.FONT_HERSHEY_PLAIN, 3, (0, 0, 255), 3, cv2.LINE_AA) 44 wide = 0 45 for i in range(50,450): 46 pxpaper = edframe[i,301] 47 if (pxpaper[0] > 130 and pxpaper[1] > 130 and pxpaper[2] > 130): 48 wide += 1 49 cv2.ellipse(edframe, (297, i), (1, 1), 0, 0, 360, (255, 0, 255)) 50 else : 51 pass 52 wide_str = str(wide) 53 cv2.putText(img, wide_str, (50, 100), 54 cv2.FONT_HERSHEY_PLAIN, 3, (255, 0, 255), 3, cv2.LINE_AA) 55 #print(wide)#, end=" ") 56 else : 57 pass 58 # 加工済の画像を表示する 59 cv2.imshow('Edited Frame', edframe) 60 cv2.imshow('img', img) 61 62 # キー入力を1ms待って、k が27(ESC)だったらBreakする 63 k = cv2.waitKey(1) 64 if k == 27: 65 break 66 67# キャプチャをリリースして、ウィンドウをすべて閉じる 68cap.release() 69cv2.destroyAllWindows() 70

投稿2018/08/20 15:18

biifun5846

総合スコア11

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

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

0

ベストアンサー

やりたいことがあまり初心者向けとは思えないのですが、
multiprocessingProcessPoolExecutor/asyncioでググるとサンプルソースがヒットするかもです。

■原因
root.mainloop() # ←の行でGUI入力待ちのブロッキングをしているからです。
そのため、whileループ内のret, frame = cap.read()の行が実行されません。
参考:Use TkInter without mainloop

■対策

動画の処理を行う部分cap.read()
tkinter表示部root.mainloop()

を分割してマルチスレッド/マルチプロセスで並列化すれば解消されるかと。
ここまでが、動画検知を行いながら+αの処理も行う方法

Tkinterにて警告を出したい

そして、質問文のこの要件があるので、動画検知側からtkinter側に通知する必要があります。
そのためにmultiprocessing#Queueを使った、producer-consumerデザインパターンを使用しました。


あまり動作確認していませんが、サンプルコードを置いておきます。ご参考まで。
個人的には、pythonのプロセスを分けた方が良いのではとも。

Python

1# -*- coding: utf-8 -*- 2import cv2 3from multiprocessing import Process, Queue 4import tkinter as tk 5from tkinter import filedialog 6 7 8root = tk.Tk() 9var_message = tk.StringVar() 10 11 12def produce(queue:Queue, file_path: str) ->None: 13 root.withdraw() # 非表示 ※これいらないかも。 14 assert file_path 15 cv2.namedWindow('Edited Frame', 1) 16 capture = cv2.VideoCapture(file_path) 17 18 while True: 19 ret, frame = capture.read() 20 if not ret: # ※readの戻り値は絶対に確認すること!!!!!!!!!!! 21 break 22 edframe = frame 23 cv2.putText(edframe, 'test', (0, 50), 24 cv2.FONT_HERSHEY_PLAIN, 3, (0, 255, 0), 3, cv2.LINE_AA) 25 cv2.line(edframe, (300, 60), (300, 400), (0, 0, 255)) 26 # cv2.circle(edframe, (100, 100), 15, (255, 255, 255), thickness=-1) 27 cv2.ellipse(edframe, (300, 230), (10, 10), 0, 0, 360, (0, 0, 255)) 28 cv2.ellipse(edframe, (300, 330), (10, 10), 0, 0, 360, (0, 0, 255)) 29 cv2.ellipse(edframe, (300, 120), (10, 10), 0, 0, 360, (0, 0, 255)) 30 px = edframe[230, 301] # y,xなので注意 31 px2 = edframe[330, 301] 32 px3 = edframe[120, 301] 33 # print("{},{},{}".format(px3,px,px2)) 34 35 # print(type(px)) 36 if (px[0] > 100 and px[1] > 100 and px[2] > 100): 37 # print("検知開始") 38 wide = 0 39 for i in range(50, 450): 40 pxpaper = edframe[i, 301] 41 if (pxpaper[0] > 130 and pxpaper[1] > 130 and pxpaper[2] > 130): 42 wide += 1 43 cv2.ellipse(edframe, (297, i), (1, 1), 0, 0, 360, (255, 0, 255)) 44 else: 45 pass 46 print(wide) # , end=" ") 47 # ※ queueに追加 表示したい文字列なり数字なりEOF以外ならなんでも良い。 48 queue.put("attention!!!!") 49 else: 50 pass 51 52 # 加工済の画像を表示する 53 cv2.imshow('Edited Frame', edframe) 54 55 # キー入力を1ms待って、k が27(ESC)だったらBreakする 56 k = cv2.waitKey(1) 57 if k == 27: 58 break 59 # ※ EOF 60 queue.put(None) 61 print("produce END") 62 cv2.destroyAllWindows() 63 64 65def on_message(queue:Queue): 66 root.withdraw() # ※ 非表示 67 item = queue.get(True) # ※ タイムアウトを指定するかはどうかは仕様によるかと。 68 if not item: # EOF 69 # ※ Windowの終了 70 print("on_message EOF") 71 root.quit() 72 return 73 var_message.set(item) 74 root.deiconify() # ※ 表示 75 # ※ デッドライン間隔、Queueに要素を追加するのが早いのならその点も考慮する事 76 root.after(1000, on_message, queue) 77 78 79def consume(queue:Queue)-> None: 80 root.title(u"コンパクター") 81 root.geometry("400x400") 82 frame1 = tk.Frame(root, pady=5) 83 frame1.pack() 84 label1 = tk.Label(frame1, font=("", 14), width=40, textvariable=var_message) 85 label1.pack(side="top") 86 root.after(0, on_message, queue) 87 root.mainloop() 88 print("consume END") 89 90 91def main() -> None: 92 # ※ ↓ファイル選択ダイアログでTopLevelウィンドウが表示されるので。 93 root.withdraw() 94 file_path = filedialog.askopenfilename(parent=root) 95 if not file_path: # isEmpty 96 return 97 print(file_path) 98 ※ producer-consumer デザインパターン 99 queue = Queue() 100 producer = Process(target=produce, args=(queue, file_path)) 101 consumer = Process(target=consume, args=(queue,)) 102 consumer.start() # ※ コンシューマから先に起動 103 producer.start() 104 producer.join() # ※ プロデューサーはjoinで終了待ちを行う。 105 106 107if __name__ == "__main__": 108 main() 109

投稿2018/08/18 04:56

編集2018/08/18 14:33
umyu

総合スコア5846

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

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

biifun5846

2018/08/18 05:11

初心者にとっては、やりたいことが特殊なのですね(笑) いっぱい分からないことが書いて頂いてるので、咀嚼しないと呑み込めない為、後日返事します!! ありがとうございます!!
biifun5846

2018/08/20 15:16 編集

編集ありがとうございます マルチプロセス関係になるので、素人向きでは無いってことですね 確かに、咀嚼するもほとんど呑み込めてません(笑) あの後いろいろ調べてみたところ、opencvのみでテキストウィンドウを追加できるみたいなので、書いてみました。自分のやりたいことですと、これでおおむね達成できそうです。 (コードのインデントがうまく機能しない為、自己解決欄に記入します) opencvがウィンドウを複数表示可能なことを知らず、Tkinterを使う質問になり、掘り下げて回答していただくことになり、お手間かけました。 ですが、マルチプロセス関係は以前すこし読んだことがあり、興味深い分野ですので、夢広がります。 例題を見てるだけでは分からない、自分のソースコードにマルチプロセスが反映してるというのは、大きな糧になると思います。 本当にありがとうございました!!
guest

0

ループの中に

root = tk.Tk() root.title(u"コンパクター") root.geometry("400x400") frame1 = tk.Frame(root, pady=5) frame1.pack() label1 = tk.Label(frame1, font=("", 14), width=40) label1.pack(side="top")

がありますが、毎回行う処理では無いのでは?
while True:
の前に記載した場合の動きを確認してみてください。

投稿2018/08/18 02:58

MasahikoHirata

総合スコア3747

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

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

biifun5846

2018/08/18 03:13

早速の回答ありがとうございます! while True:の前に持ってきましたが、止まり方に変化が出ただけで(Tkinterウィンドウとopencvウィンドウが出て止まりTkinterウィンドウを消すと動画が動き出す)、動画はストップしてしまいます。
biifun5846

2018/08/18 03:27

root.mainloop() を記述しないと、Tkinterのウィンドウが出ないみたいですが、Tkinterがループすると、ほかの処理が止まってしまいます。入力ウィンドウなどはループが必要ですが、警告等の表示だけなら要らないような気がしましたので、1週間ほどググって調べていますが、英語が拙いことがあって探し出すことが出来ませんでした。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問