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

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

ただいまの
回答率

88.78%

Tkinterのウインドウ内にwebカメラから取得した動画を表示したい

解決済

回答 1

投稿 編集

  • 評価
  • クリップ 4
  • VIEW 6,842

2ckD

score 52

前提

  • Python
  • Tkinter
  • OpenCV
  • webカメラ

実現したいこと

OpenCVでwebカメラから取得した画像(動画)をウインドウ内に表示したいです。

発生している問題

  1. 番号リストcv2.imshowならスムーズに画像が切り替わりますが、
    別ウインドウを開く必要があります。そうすることなく動画を表示したいです。
  2. canvas.itemconfig()で画像を切り替えようとすると、
    画像が消える(一瞬canvasの背景色のみが表示される)→画像が表示される
    というプロセスを経るためにスムーズに画像を切り替えることができません。

該当のソースコード

import tkinter as tk
import threading as th
import cv2
from PIL import Image,ImageTk
import numpy as np

root=tk.Tk()
root.title("camera")
root.geometry("720x480")
canvas=tk.Canvas(root, width=640, height=480)
canvas.pack()

def camera():
    try:
        c=cv2.VideoCapture(0)
        h=c.get(cv2.CAP_PROP_FRAME_HEIGHT)
        w=c.get(cv2.CAP_PROP_FRAME_WIDTH)
        i=0
        while(True):
            ret, frame =c.read()
            if (not ret):
                break
            if cv2.waitKey(1)&0xFF==ord('q'):
                canvas.delete("all")
                break
            cv2.imshow('camera', frame)
            image=ImageTk.PhotoImage(Image.fromarray(cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)))
            if not i:#初回起動時の処理
                i=1
                canvas.create_image(w/2,h/2,image=image,tag="img")
                continue
            canvas.itemconfig("img", image=image)
        c.release()
        cv2.destroyAllWindows()
    except:
        import sys
        print(sys.exec_info()[0])
        print(sys.exec_info()[1])

t1=th.Thread(target=camera)
t1.start()
root.mainloop()

試したこと

labelで画像を表示する場合も同じ結果に終わりました。

label.configure(image=image)

回答をもとにできたもの

aaaa

import tkinter as tk
import cv2
from PIL import Image,ImageTk
import numpy as np

root=tk.Tk()
root.title("camera")
root.geometry("720x480")
root.resizable(width=False, height=False)
canvas=tk.Canvas(root, width=640, height=480, bg="white")
canvas.pack()

def capStart():
    print('camera-ON')
    try:
        global c, w, h, img
        c=cv2.VideoCapture(0)
        w, h= c.get(cv2.CAP_PROP_FRAME_WIDTH), c.get(cv2.CAP_PROP_FRAME_HEIGHT)
        print('w:'+str(w)+'px+h:'+str(h)+'px')
    except:
        import sys
        print("error-----")
        print(sys.exec_info()[0])
        print(sys.exec_info()[1])
        '''終了時の処理はここでは省略します。
        c.release()
        cv2.destroyAllWindows()'''

def u():#update
    global img
    ret, frame =c.read()
    if ret:
        img=ImageTk.PhotoImage(Image.fromarray(cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)))
        canvas.create_image(w/2,h/2,image=img)
    else:
        print("u-Fail")
    root.after(1,u)

capStart()
u()
root.mainloop()
  • 気になる質問をクリップする

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

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

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 過去に投稿した質問と同じ内容の質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 1

checkベストアンサー

+1

自分では試していなくて申し訳ないのですが、こちらのサンプル では、window.after() を使って指定時間(ms)ごとに canvas.create_image() で frame を更新する例が示されています。これの App.update() 関数を見ると、canvas.create_image() しか使っていませんが、それだけだと画像が切り替わらないのでしょうか?

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2019/05/06 04:25

    実はそのサイトはすでに見ていたのですが、
    whileの中に「canvas.create_image() 」を入れる方法で失敗したあとだったのでやっても無駄だと読み飛ばしちゃっていました。

    回答を頂いてから、コピペして実行したらimshow()した時と同じようにスムーズに再生することができました。
    ありがとうございました。

    今回、クラスを作成せずに作りたかったので、
    参考にしたものとはちょっと違う修正版も今後誰かの役に立つかもしれないので残しておきます。

    キャンセル

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

  • ただいまの回答率 88.78%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

関連した質問

同じタグがついた質問を見る