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

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

ただいまの
回答率

87.77%

アニメーショングラフを表示させたい

受付中

回答 0

投稿 編集

  • 評価
  • クリップ 0
  • VIEW 533

score 27

画面上で円が動く動画があります。
その円を取得して座標(X,Y)を求めてフレームごとにXとYをプロットした
グラフをアニメーション(リアルタイム)で表示させたいです。

円を取得して、アニメーショングラフを作成してみたのですが
Traceback (most recent call last):
File "C:\Users\User\AppData\Local\Continuum\anaconda3\lib\site-packages\matplotlib\cbook\init.py", line 216, in process
func(*args, **kwargs)
File "C:\Users\User\AppData\Local\Continuum\anaconda3\lib\site-packages\matplotlib\animation.py", line 953, in _start
self._init_draw()
File "C:\Users\User\AppData\Local\Continuum\anaconda3\lib\site-packages\matplotlib\animation.py", line 1523, in _init_draw
artist.set_visible(False)
AttributeError: 'list' object has no attribute 'set_visible'とエラーがでます。
いろいろ調べてみたのですが改善できません。
どなたかご教授いただけないでしょうか。

追記1)
ims.append(lines)でエラーが出ないようになりました。
ですが、グラフ画面が表示されたまま処理が止まります。
グラフ画面の×ボタンを押すとまたグラフ画面が表示されます。
何回か押しているとグラフの線が画面に表示されてきたので、
×ボタンを押すごとに1フレームごと処理が進んでいるみたいです。
どなたかご教授ください。

追記2)
plt.pauseで処理が止まらなくなりました。
ですが、1フレームごとにグラフが表示されています。
やりたいこととしては下記になります。
1.animation.ArtistAnimation()でims = []を取り込んで?
グラフを表示したままにしてリアルタイムで表示する。
2.ims = []に値を入れるまでの処理を進めて、動画を表示する

追記3)
追記2は解決しました。
cv2.imshow('MotionDetected Area Frame', frame)以下参照

下記のコードを実行すると、
TypeError: 'list' object is not callableとエラー出ます。
im= plt.plot(lengh, circle_x)が1フレーム目では問題ないですが、
2フレーム目にこのエラーが表示されます。
どなたかご教授ください。

import cv2
import time
from matplotlib import pyplot as plt
import matplotlib.animation as animation
import numpy as np


# 動画ファイルを読み込みclassオブジェクトに入れる
cap = cv2.VideoCapture(ファイルパス)

cap_fps = cap.get(cv2.CAP_PROP_FPS)

fig = plt.figure()  # Figureを作成
ims = []
lines = []
xmax = 2500
xmin = 0
ymax = 300
ymin = 200

mean_box = []
circle_x = []
circle_y = []
circle_r = []

# <cap:class>のget関数の引数で取得する数値を決定する。(この場合総フレーム数)
frame_count = cap.get(cv2.CAP_PROP_FRAME_COUNT)
# timeクラスのタイム関数((注)動画ファイルの実時間ではなく、プログラムの実行時間として使用)
# 後でfpsの確認とかにも使う
start = time.time()
# フレームカウント用
i = 0
# 無限ループ

def calc_mean(sig, center, radius):
    # 計算対象の領域は255, それ以外の領域は0としたマスク画像を作成する。
    mask = np.zeros_like(sig)  # すべての画素が0の画像
    cv2.circle(mask, center, radius, color=255, thickness=-1)  # 円を描画
    # cv2.imshow("sss",mask)
    cv2.imwrite("mask.png", mask)  # デバッグ用
    # AND 演算
    roi = cv2.bitwise_and(sig, mask)
    # cv2.imshow("sss", roi)
    cv2.imwrite("roi.png", roi)  # デバッグ用
    # 輝度値の平均を計算する。
    n_pixels = (mask == 255).sum()  # 計算対象の領域の画素数
    # mean = roi[roi < 150].sum() / n_pixels # 平均輝度値
    mean = roi.sum() / n_pixels  # 平均輝度値
    return mean

while True:
    start2 = time.time()
    jikan2 = time.time() - start2
    # 画像を順番にを取り込む(第二返り値が各フレーム)
    ret, frame = cap.read()
    # フレームカウント
    i += 1
    # cap.read()の返り値がなかった場合、処理を中止

    if frame is None:
        print(i, 'break')
        break
    # 三次元配列で格納されたBGRをGrayScaleに変換して二次元配列とする
    # 例[[[100,100,100][105,120,140]...]] ⇒ [[100,120...]]
    # ((注)Opencvにおいて一般的なRGBの並びではなくBGRで読み込まれる)

    # ####グレースケール画像に変換 #### S
    gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
    # ####グレースケール画像に変換 #### E

    # #### 円の位置をある程度推定する ####
    frame = frame[50:480, 50:640]
    dst = gray[50:480, 50:640]
    # cv2.imshow("triming", dst)

    # 閾値の設定
    threshold = 40

    # 二値化(閾値100を超えた画素を255にする。)
    ret, nck = cv2.threshold(dst, threshold, 255, cv2.THRESH_BINARY)

    # 経過時間
    jikan = time.time() - start  # 現在の経過時間

    # fps
    # if jikan is 0.0:
    if jikan < 0.001:
        # fps = frame_no / jikan  # frame per seconds
        cv2.putText(frame, "例外", (10, 50), cv2.FONT_HERSHEY_SIMPLEX, 0.5, (255, 0, 0), 1, cv2.LINE_AA)
    else:
        circles = cv2.HoughCircles(nck, cv2.HOUGH_GRADIENT, dp=2, minDist=0.07,
                                   param1=1520, param2=10, minRadius=74, maxRadius=77)
        print(circles, "iii")

        if circles is None:
            cv2.putText(dst, "false2", (10, 50), cv2.FONT_HERSHEY_SIMPLEX, 0.5, (255, 0, 0), 1, cv2.LINE_AA)
        else:
            circles = np.uint16(np.around(circles))

            circles = circles.squeeze(axis=0)  # (1, NumCircles, 3) -> (NumCircles, 3)

            for cx, cy, r in circles:

                # 輝度値最小の円を取得する
                mean = calc_mean(nck, center=(cx, cy), radius=r)
                # print(mean)
                mean_box.append(round(mean, 5))
                min_idx = np.argmin(mean_box)  # 輝度値が最小の要素のインデックスを取得
                cx, cy, r = circles[min_idx]  # 対応する円を取得
                # 輝度値最小の円を取得する

        # draw the outer circle
        frame = cv2.circle(frame, (cx, cy), r, (0, 255, 0), 2)
        # draw the center of the circle
        frame = cv2.circle(frame, (cx, cy), 2, (0, 0, 255), 3)
        # print(circles)
        circle_x.append(cx)
        circle_y.append(cy)
        circle_r.append(r)
        mean_box.clear()

    cv2.imshow('MotionDetected Area Frame', frame)

    if i==1:
        lengh = range(0, len(circle_x), 1)
        im= plt.plot(lengh, circle_x)
        lines.extend(im)
        ims.append(lines)

        ani = animation.FuncAnimation(fig, ims, interval=1)

    else:
        plt.cla()
        lengh = range(0, len(circle_x), 1)
        im= plt.plot(lengh, circle_x)
        lines.extend(im)
        ims.append(lines)
        plt.xlim(xmin, xmax)
        plt.ylim(ymin, ymax)
        # ani.save("plot2.gif", writer='imagemagick')
        # ani.save('anim.mp4', writer="ffmpeg")
        plt.pause(0.001)

    k = cv2.waitKey(1)
    if k == 27:
        break

cap.release()
cv2.destroyAllWindows()
  • 気になる質問をクリップする

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

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

    クリップを取り消します

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

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

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

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

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

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

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

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

    質問の評価を下げる

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

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

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

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

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

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

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

    詳細な説明はこちら

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

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

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

質問への追記・修正の依頼

  • bsk

    2020/09/24 18:07 編集

    plt.show()だとウィンドウを閉じるまで処理ストップするので、アニメーションさせたいならplt.pauseで適当な時間を入れれば動くと思いますよ。

    キャンセル

  • MATLIB

    2020/09/28 10:35

    回答ありがとうございます。
    plt.pauseで処理が止まらなくなりました。
    別の問題がでたので、質問内容に追記しました。

    キャンセル

  • MATLIB

    2020/09/30 13:47

    下記のコードを実行すると、
    TypeError: 'list' object is not callableとエラー出ます。
    im= plt.plot(lengh, circle_x)が1フレーム目では問題ないですが、
    2フレーム目にこのエラーが表示されます。
    どなたかご教授ください。

    キャンセル

まだ回答がついていません

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

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

関連した質問

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