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

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

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

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

Python

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

Q&A

1回答

780閲覧

tkinterで動画を読み込むと途中で応答なしになる

kenas1

総合スコア0

Tkinter

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

Python

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

0グッド

0クリップ

投稿2021/04/28 16:46

編集2021/04/30 05:59

#質問
tkinterで動画を読み込んで遊ぼうと思ったのですが、読み込み途中で応答なしとなります。時間経過できちんと読み込みは終わるのですが、途中で応答なしにならないようにするにはどうしたらいいのか、教えて頂きたいです。

Python

1 2import os 3import numpy as np 4import tkinter as tk 5from tkinter import filedialog 6import cv2 7 8# 画面作成 9root = tk.Tk() 10root.geometry("640x480") 11root.configure(bg='white') 12 13def pushed(): 14 b_text.set("読み込み") 15 fTyp = [("","*")] 16 iDir = os.path.abspath(os.path.dirname(__file__)) 17 file = filedialog.askopenfilename(filetypes = fTyp,initialdir = iDir) 18 19 if file: 20 vidcap=cv2.VideoCapture(file) 21 frames = int(vidcap.get(cv2.CAP_PROP_FRAME_COUNT)) 22 data=v_load(vidcap,frames) 23 24#動画読み込み 25def v_load(vidcap,frames): 26 data=[] 27 for i in range(frames): 28 _,imgs=vidcap.read() 29 data.append(np.average(imgs[:,:,1])) 30 31 return data 32# ボタン作成 33b_text=tk.StringVar() 34b_text.set("アップロード") 35btn = tk.Button(root, textvariable=b_text, width=14,command=pushed) 36# 配置 37btn.place( 38 x=100, 39 y=400 40) 41 42root.mainloop()

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

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

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

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

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

teamikl

2021/04/30 01:54

質問: root.mainloop() が2回ありますが意図通りですか? 動画の再生を想定して回答してしまいましたが、 「すべて読み込む」事自体が目的ですか? 目的によっては、適切な対処方法は変わってきます。
kenas1

2021/05/01 16:40

root.mainloop() が2回あるのは単純なミスでした。 動画を「すべて読み込む」事自体が目的です!
teamikl

2021/05/01 17:34

読み込むだけであれば、スレッドやプロセスを別けることで「応答なし」自体は回避できます。 ただし、その後に結果をGUIへ反映しようとすると、回答にて説明したとおり 何れにしても Queue や タイマーの導入は必要になってきます。
guest

回答1

0

問題点:

  • イベントループ内での時間のかかる処理
  • 全てのフレームを一度に読み込んでいる

解決策:

  • 時間のかかる処理を分割、イベントループを止めないようにプログラムを組む。
  • 描画に必要なフレームのみを読み出す。

GUIライブラリの提供するタイマー(tkinterではafter関数)を使う実装方法を検討してみてください。

関連:

 ※ 動画再生では有りませんが、時間のかかるforループを、ジェネレータにしてタイマーで処理する方法。


「応答なし」への対策は、イベントループ(tkinterではmainloop)の理解が必須で

python

1def mainloop(): 2 while True: 3 イベント処理 # ここで pushed() -> v_load() 呼出 4 描画更新

イベントループ内部は、(実際のコードではありませんが)上記のような感じになっていて

イベント処理 → 描画更新 → イベント処理 → 描画更新 ...

と、「順番に」実行されます。

順番に実行されるので、時間のかかる処理が終わるまでは、
その次・他の処理は行われない状態で、これが「応答なし」になる原因です。

このようなループ内で実行されるという点に留意してください。

GUI等の「イベント駆動型プログラミング」全般に言えることですが、
応答なしのような状況を避けるために
イベントループ内から呼び出される関数は、直ぐに処理を終えて
ループに処理を戻さなければなりません。

具体的には、以下のような操作は、イベントループ内では原則禁止です。
(イベントループ内 ⇛ ボタンクリック等のイベント発生時に呼び出される関数)

  • 時間のかかる for/while ループ、関数の再帰呼び出し
  • I/O 等でのブロッキング操作 (ネットワークやデータベースへの読書)
  • time.sleep

この場合であれば、ボタンを押したときに呼び出される関数
pushed() 内の v_load() 動画ファイルから全フレームをリストに読み出し
のループが該当します。

「時間がかかる」ことが問題なので、
動画ファイルのサイズ次第では問題にならないこともありますが、
対策としては、「分割して必要なデータのみを読み込む」ようにする方が良いです。

時間のかかる処理がある場合は、イベントループの処理を阻害しないように
工夫が必要になります。

  • GUIの提供するタイマー (tkinter では after関数) で分割して実行
  • マルチスレッド (threading)
  • 非同期 I/O (asyncio)

解決策としては、いくつか段階を踏んでの実装をおすすめします。

まずはタイマーを使い、動画を再生(描画更新)しながら、
逐次、必要なフレームのみを読み出す方法で実装しましょう。

その後に、フレームの読み出し部分を別スレッドで行う方法で、
改良を重ねていくと良いと思います。


改良案: スレッドの導入 (必須では有りません。長くなってしまったので分割)

  • read() でのブロッキングの回避方法

 案A: non-blocking mode で読み出す
案B: スレッドを使う

  • マルチスレッドにする際の注意点 -> Queue を使う

直面している問題とは別問題ですが、
read() は、「I/O 等でのブロッキング操作」に該当するので、
障害時等の稀なケースですが、read() が反応を返さず、
「応答なし」になる可能性は残ります。

案A: イベントループ内で呼び出す場合は、timeout を設定する等、
non-blocking mode で読み出す方法を調べてください。
案B: 別スレッドでフレーム読み出しとした方が良いです。

別スレッド導入の際の注意点としては、
別スレッドからのGUI操作は、スレッド安全ではないので、
描画更新は、GUIのイベントループ側から行う必要があります。

v_load() を別スレッドで実行すれば、「応答なし」自体は回避できますが
別スレッドから直接GUIへ描画してはいけない点に注意してください。
スレッドを用いる場合、Queue を用いて通知し、
イベントループからタイマーで逐次読み出しという手順を取ります。

補足: tkinter ではライブラリ内部でもスレッドが使われているため、
別スレッドからGUIを操作するコードでも、エラーなく実行出来ます。
ですが、イベントループに対する割り込み操作になるため、安全な操作では有りません。
問題が起きた時のデバッグが困難で、再現が難しい問題の原因になります。

投稿2021/04/30 01:32

編集2021/04/30 01:46
teamikl

総合スコア8664

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

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

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

まだベストアンサーが選ばれていません

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

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

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

ただいまの回答率
85.46%

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

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

質問する

関連した質問