動画の中を移動する物体の動きをトラッキング(追跡)することが出来れば、その物体の変位や速度、加速度といった物理量を計算することが出来ます。ここでは、Python/OpenCVを使って動画内物体トラッキングコードの例を紹介します。
こんにちは。wat(@watlablog)です。本日は動画処理の例題として、物体トラッキングの方法を紹介します!
物体トラッキング処理で得る情報
トラッキングとは?
トラッキング(Tracking)とは、日本語で「追跡」を意味する単語です。
言葉の使われ方は分野によって様々ですが、例えばマーケティング分野では、インターネットを閲覧しているユーザがどのページを見てどのリンクを辿ったかを調べることもトラッキングと呼びます。
また信号処理の分野では、回転体のFFT分析でわかる回転次数の変化を追うこともトラッキングと呼びます。
このページでは動画内の物体の移動を追跡する内容を扱い、同じくトラッキングと呼びます。
物体トラッキングでわかること
軌跡(変位)がわかる
動画から物体の動きを追跡するという処理は、そのままで軌跡情報が得られていることになります。
物理や工学の実験では着目している物体がどの方向にどれだけ動いたかを知ることは、事象の理解にとても重要です。
変位センサ、GPSセンサを付けられる規模であれば良いのですが、微小範囲を取り扱ってセンサを付けることが出来なかったり、そもそもセンサを取付けることで事象の変化が懸念される場合等は動画で分析することが多々あります。
速度や加速度がわかる
動画で軌跡や変位が数値としてわかるということは、速度や加速度といった情報も同時に得ることが可能です。
動画撮影や動画ファイルにはFPS(Frames Per Second)、フレームレートとも呼ばれる時間情報を持っています。
変位と速度、加速度はそれぞれ時間による微積分関係にあるため、FPS情報が取得できれば算出可能となります。
物体トラッキング手順の例
ここで、物体トラッキング手順の例を紹介していきます。「~例」としているのは、このトラッキング技術はケースによって様々な手法を使い分ける必要があり、万能な方法がないからです。
ここでは物体の特徴量として輪郭情報を検出し、その情報から位置座標を取得する方法を紹介します。
あくまで一例ですので、異なる物体特徴量検出の方法を覚えたらそれは物体トラッキングの手段が増えたことにもなります。
他の例では、ディープニューラルネットワークを使った検出が最新技術でしょうか。CNNやYOLOといったキーワードで検索すると色々出て来ますね。これらはAI技術ですが、ご興味があればAIカテゴリのページも是非見てみて下さい!
動画内物体の輪郭から位置を特定するために必要な画像処理技術
動画のフレーム処理
動画内の物体トラッキングをするためには、まずは動画ファイルを扱う方法を知る必要があります。
動画といってもパラパラ漫画のような多数のフレームで構成されています。そのため、基本はフレームに対する画像処理をする方法を覚えておけば問題ありません。
以下の記事はそれぞれ「動画のフレームに対しある画像処理をする」という内容ですので、必要であれば是非ご覧下さい。
「Python/OpenCVで動体検知!動画の動いている部分を検出」
「Python動画編集!動画に位置制御したテロップを入れる方法」
「Pythonでブログの広告が目立つかどうか「動的」に評価する方法」
グレースケール化と二値化
今回は動画の各フレーム画像に対し、物体の輪郭を検出する手法を使います。
輪郭を始めとする様々な特徴量の抽出には、カラー画像をそのまま扱うのではなく、グレースケール化したり二値化したりといった前処理を行うことが一般的です。
以下の記事はグレースケール化や二値化に関する内容ですので、こちらも必要に応じてご覧下さい。
「Python/OpenCVで画像の二値化をする方法」
「Python/OpenCVの適応的閾値処理で綺麗な二値化!」
輪郭検出処理
本題の輪郭抽出方法ですが、輪郭は上記グレースケール化と二値化処理を使って行います。
詳しくは以下の記事に記載しましたので、併せてご覧下さい。
「Python/OpenCVで画像内オブジェクトの輪郭抽出をする」
輪郭から物体トラッキングをするPythonコード
サンプル動画
今回コードのテストで使用するサンプル動画を以下のYoutube動画に示します。ダウンロードボタンも付けましたので、是非サンプルコードと合わせてお試しください。
…かなり適当感はありますが、当WATLABブログのロゴマークを黒い背景の中で動かしてみました。
ロゴマークは背景の中を振幅100[pix]の正弦波で動いています。
動作環境
本コードは以下のPython環境で動作を確認しました。
Python | Python 3.9.6 |
---|---|
PyCharm (IDE) | PyCharm CE 2020.1 |
Numpy | 1.21.1 |
matplotlib | 3.4.3 |
opencv-python | 4.2.0.34 |
全コード
先ほどのサンプル動画に対し、物体トラッキングをする全コードを以下に示します。ポイントは輪郭検出を行っているdef関数です。
輪郭検出で得られたcontoursには輪郭の座標情報が格納されています。この座標情報をx, y軸それぞれで平均をとったものを物体の座標としています。
その他は既に紹介した記事内容と同じです。
しかし、今回はカラー画像を扱っているので、VideoWriterの最後の引数がTrueになっている点が注意点です(これをFalseにすると動画が正常に保存されない)。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 |
import numpy as np import cv2 from matplotlib import pyplot as plt # 画像から輪郭を検出する関数 def contours(img): img_gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) # グレースケール化 ret, img_binary = cv2.threshold(img_gray, # 二値化 60, 255, # 二値化のための閾値60(調整要) cv2.THRESH_BINARY) contours, hierarchy = cv2.findContours(img_binary, # 輪郭検出 cv2.RETR_EXTERNAL, # 外側の輪郭のみ抽出 cv2.CHAIN_APPROX_SIMPLE) contours = np.array(contours) # 輪郭情報をndarrayに変換 x = np.mean(contours[0].T[0, 0]) # 輪郭のx方向平均値を算出 y = np.mean(contours[0].T[1, 0]) # 輪郭のy方向平均値を算出 return x, y movie = cv2.VideoCapture('video.mp4') # 動画ファイルの読み込み # 動画ファイル保存用の設定 fps = int(movie.get(cv2.CAP_PROP_FPS)) # 動画のFPSを取得 w = int(movie.get(cv2.CAP_PROP_FRAME_WIDTH)) # 動画の横幅を取得 h = int(movie.get(cv2.CAP_PROP_FRAME_HEIGHT)) # 動画の縦幅を取得 fourcc = cv2.VideoWriter_fourcc('m', 'p', '4', 'v') # 動画保存時のfourcc設定(mp4用) video = cv2.VideoWriter('video_out.mp4', fourcc, fps, (w, h), True) # 動画の仕様(ファイル名、fourcc, FPS, サイズ, カラー) # ファイルからフレームを1枚ずつ取得して動画処理後に保存する x_list = [] y_list = [] while True: ret, frame = movie.read() # フレームを取得 # フレームが取得できない場合はループを抜ける if not ret: break x, y = contours(frame) # 輪郭検出から物体中心を算出 frame = cv2.circle(frame, (int(x), int(y)), 30, (0, 255, 0), 3) # 検出した位置にサークル描画 video.write(frame) # 動画を保存する x_list.append(x) y_list.append(y) # 動画オブジェクト解放 movie.release() |
実行結果
以下の動画が実行結果です。
移動する物体に対しcv2.circleで円を描画していますが、見事にトラッキング出来ている結果を得ました。
おまけ1:軌跡情報の取得
以下はおまけですが、このコードを先ほどのコードの一番下に追加することで、グラフ表示が出来ます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 |
# ここからグラフ描画 # フォントの種類とサイズを設定する。 plt.rcParams['font.size'] = 14 plt.rcParams['font.family'] = 'Times New Roman' # 目盛を内側にする。 plt.rcParams['xtick.direction'] = 'in' plt.rcParams['ytick.direction'] = 'in' # グラフの上下左右に目盛線を付ける。 fig = plt.figure() ax1 = fig.add_subplot(111) ax1.yaxis.set_ticks_position('both') ax1.xaxis.set_ticks_position('both') # スケール設定 ax1.set_xlim(0, 800) ax1.set_ylim(0, 400) # 軸のラベルを設定する。 ax1.set_xlabel('x') ax1.set_ylabel('y') # データプロット ax1.scatter(x_list, y_list, label='Tracking result') plt.legend() fig.tight_layout() # グラフを表示する。 plt.show() plt.close() |
以下のグラフが軌跡です。綺麗な正弦波を得ることが出来ました。
縦軸は画像の場合下が正ですが、このグラフは上が正になっていることに注意が必要です。
このように軌跡情報が数値であれば、後は既に得ているFPS情報を使って時間の関数にすることも可能ですね。
おまけ2:軌跡情報を元動画に描画する
先ほどの軌跡情報(xy座標)を元動画に重ね描きするコードを以下に示します。
「#軌跡を残しつつマーカを描画(軌跡を連続とするために新規frameには過去の座標分もforで描画している)」の部分が主な変化点ですが、コードを関数化したりdocstringを使って関数の冒頭に説明を書いたりしてみました。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 |
import numpy as np import cv2 import os def contours(img): """画像から輪郭を検出する関数 :param img:画像 :return:x座標, y座標 """ img_gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) # グレースケール化 ret, img_binary = cv2.threshold(img_gray, # 二値化 60, 255, # 二値化のための閾値60(調整要) cv2.THRESH_BINARY) contours, hierarchy = cv2.findContours(img_binary, # 輪郭検出 cv2.RETR_EXTERNAL, # 外側の輪郭のみ抽出 cv2.CHAIN_APPROX_SIMPLE) contours = np.array(contours) # 輪郭情報をndarrayに変換 x = np.mean(contours[0].T[0, 0]) # 輪郭のx方向平均値を算出 y = np.mean(contours[0].T[1, 0]) # 輪郭のy方向平均値を算出 return x, y def tracking(filename: str): """動画から輪郭を抽出、軌跡を描画して新しい動画を作る関数 :param filename: 元動画ファイル名.mp4 """ # 動画読み込み movie = cv2.VideoCapture(filename) # 動画ファイル保存用の設定 fps = int(movie.get(cv2.CAP_PROP_FPS)) w = int(movie.get(cv2.CAP_PROP_FRAME_WIDTH)) h = int(movie.get(cv2.CAP_PROP_FRAME_HEIGHT)) fourcc = cv2.VideoWriter_fourcc('m', 'p', '4', 'v') # 元ファイルを引継ぎ保存するためのファイル名(元ファイル_out.元ファイルの拡張子)を生成 name, ext = os.path.splitext(filename) out_path = name + '_out' + ext # 動画の仕様(保存するファイル名、fourcc, FPS, サイズ, カラー) video = cv2.VideoWriter(out_path, fourcc, fps, (w, h), True) # ファイルからフレームを1枚ずつ取得して動画処理後に保存する x_list = [] y_list = [] while True: ret, frame = movie.read() # フレームを取得 # フレームが取得できない場合はループを抜ける if not ret: break # 輪郭検出から物体中心を算出 x, y = contours(frame) # 座標をリストに追加 x_list.append(x) y_list.append(y) # 軌跡を残しつつマーカを描画(軌跡を連続とするために新規frameには過去の座標分もforで描画している) for i in range(len(x_list)): frame = cv2.drawMarker(frame, (int(x_list[i]), int(y_list[i])), color=(255, 255, 255), markerType=cv2.MARKER_CROSS, markerSize=10, thickness=1, line_type=cv2.LINE_4) # 検出した位置にサークル描画 # frame = cv2.circle(frame, (int(x), int(y)), 30, (0, 255, 0), 3) # 動画とするためにフレームを追加する video.write(frame) # 動画オブジェクト解放 movie.release() return if __name__ == '__main__': filename = 'video.mp4' tracking(filename) |
結果は以下です(YouTube動画視聴で確認できますが、ダウンロードも可)。今回はマーカを使いましたが、cv2には他にも線や円を描いたりできますのでアレンジ可能です。
おまけ3:グラフの横軸を時間軸にする
おまけ1で作ったグラフの横軸を時間軸にしてみます。
既に動画を読み込む時に「# 動画ファイル保存用の設定」部分でfps(1秒当たりのフレーム数)を抽出していますので、動画のコマ間隔は時間に変換可能です。
以下のコードは全コードを示していますが(書き方も関数でまとめたりしています)、def tracking()の最後で時間軸tを作成してみました。抽出した座標情報と同じだけの長さに時間分解能dtをかけているだけです。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 |
import numpy as np import cv2 import os from matplotlib import pyplot as plt def contours(img): ''' 画像から輪郭を検出する関数 ''' img_gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) # グレースケール化 ret, img_binary = cv2.threshold(img_gray, # 二値化 60, 255, # 二値化のための閾値60(調整要) cv2.THRESH_BINARY) contours, hierarchy = cv2.findContours(img_binary, # 輪郭検出 cv2.RETR_EXTERNAL, # 外側の輪郭のみ抽出 cv2.CHAIN_APPROX_SIMPLE) contours = np.array(contours) # 輪郭情報をndarrayに変換 x = np.mean(contours[0].T[0, 0]) # 輪郭のx方向平均値を算出 y = np.mean(contours[0].T[1, 0]) # 輪郭のy方向平均値を算出 return x, y def tracking(filename): ''' 動画から輪郭を抽出、軌跡を描画して新しい動画を作る関数 ''' # 動画読み込み movie = cv2.VideoCapture(filename) # 動画ファイル保存用の設定 fps = int(movie.get(cv2.CAP_PROP_FPS)) w = int(movie.get(cv2.CAP_PROP_FRAME_WIDTH)) h = int(movie.get(cv2.CAP_PROP_FRAME_HEIGHT)) fourcc = cv2.VideoWriter_fourcc('m', 'p', '4', 'v') # 元ファイルを引継ぎ保存するためのファイル名(元ファイル_out.元ファイルの拡張子)を生成 name, ext = os.path.splitext(filename) out_path = name + '_out' + ext # 動画の仕様(保存するファイル名、fourcc, FPS, サイズ, カラー) video = cv2.VideoWriter(out_path, fourcc, fps, (w, h), True) # ファイルからフレームを1枚ずつ取得して動画処理後に保存する x_list = [] y_list = [] while True: ret, frame = movie.read() # フレームを取得 # フレームが取得できない場合はループを抜ける if not ret: break # 輪郭検出から物体中心を算出 x, y = contours(frame) # 座標をリストに追加 x_list.append(x) y_list.append(y) # 軌跡を残しつつマーカを描画(軌跡を連続とするために新規frameには過去の座標分もforで描画している) for i in range(len(x_list)): frame = cv2.drawMarker(frame, (int(x_list[i]), int(y_list[i])), color=(255, 255, 255), markerType=cv2.MARKER_CROSS, markerSize=10, thickness=1, line_type=cv2.LINE_4) # 検出した位置にサークル描画 # frame = cv2.circle(frame, (int(x), int(y)), 30, (0, 255, 0), 3) # 動画とするためにフレームを追加する video.write(frame) # 動画オブジェクト解放 movie.release() # 時間軸の作成(FPS(=1秒間のフレーム数)情報より) dt = 1 / fps t = np.arange(0, len(x_list), 1) * dt return x_list, y_list, t def plot(x_list, y_list, t): ''' 結果を描画する関数 ''' # ここからグラフ描画 # フォントの種類とサイズを設定する。 plt.rcParams['font.size'] = 14 plt.rcParams['font.family'] = 'Times New Roman' # 目盛を内側にする。 plt.rcParams['xtick.direction'] = 'in' plt.rcParams['ytick.direction'] = 'in' # グラフの上下左右に目盛線を付ける。 fig = plt.figure() ax1 = fig.add_subplot(211) ax1.yaxis.set_ticks_position('both') ax1.xaxis.set_ticks_position('both') ax2 = fig.add_subplot(212) ax2.yaxis.set_ticks_position('both') ax2.xaxis.set_ticks_position('both') # 軸のラベルを設定する。 ax1.set_xlabel('time [s]') ax1.set_ylabel('x [pix]') ax2.set_xlabel('time [s]') ax2.set_ylabel('y [pix]') # データプロット ax1.plot(t, x_list, label='x', marker='o') ax2.plot(t, y_list, label='y', marker='o') fig.tight_layout() # グラフを表示する。 plt.show() plt.close() return if __name__ == '__main__': filename = 'video.mp4' x_list, y_list, t = tracking(filename) plot(x_list, y_list, t) |
結果はこちら。画像はxとyの2軸あるので2つのグラフで書いてみました。x方向はただまっすぐ進み、y方向は振動している特徴が時間で追えるようになりました。
まとめ
本記事では動画から各フレームを取得し、フレームに対しグレースケール化と二値化処理を施し輪郭抽出を行い、輪郭情報から位置座標を連続的に取得することで軌跡を得るPythonコードを紹介しました。
動画処理は基本を習得すればどれも同じような流れなので、今後も何か画像処理を覚えたら動画へも応用してみたいと思います。
今回は輪郭情報からトラッキングをしてみましたが、他にも色々な手法がありそうですね!
Twitterでも関連情報をつぶやいているので、wat(@watlablog)のフォローお待ちしています!
質問です.このプログラムをjuypter notebookで実行したのですが何も表示されません
どうすれば動画を再生することができますか?
なお,動画のファイルパスは # 動画ファイルの読み込みでは643771049.410572.mp4
video = cv2.VideoWriter(‘video_out.mp4’, fourcc, fps, (w, h), True) # 動画の仕様(ファイル名、fourcc, FPS, サイズ, カラー)では/users/名/Downloads/~.mp4としています
osはmac Catalinaです
よろしくお願いします
ご訪問ありがとうございます。
本プログラムはトラッキングを行った結果を描画した動画の保存までなので、
動画を実際に再生するには保存されたファイルをご自身で実行する必要があります。
Pythonで再生まで行うには別途コード追加が必要です。
以上、よろしくお願い致します。
コメント失礼します。
少しお聞きしたいことがあります。
こちらのサイトを参考にさせて頂いているのですが、ある動画に対してトラッキングをかけたいのですが上手く反応してくれません。その動画自体に問題があるのか、何が問題なのかが分かりません。その点について教えて頂きたくコメントさせて頂きました。よろしければ返信の方、お待ちしております。
ご訪問ありがとうございます。
この記事では二値化ではっきりとトラッキング対象物が区別できるものしか対応できないと思います。
動画の背景や対象物によってはなかなか反応悪くなるかも知れません。
代替案として、以下のようにパターンマッチングを利用する方法もあります。
「https://watlab-blog.com/2021/02/04/pattern-match-tracking/」
いつでも万能のトラッキングができるコード、は難しいですので、ケースバイケースで工夫する必要があると思っています。
以上、何か不明点ございましたらお気軽にコメントください。
よろしくお願い致します。
質問です。
写経し、このプログラムを実行しようとしたところ、以下のエラーが出ました。
py:14: VisibleDeprecationWarning: Creating an ndarray from ragged nested sequences (which is a list-or-tuple of lists-or-tuples-or ndarrays with different lengths or shapes) is deprecated. If you meant to do this, you must specify ‘dtype=object’ when creating the ndarray.
contours = np.array(contours) # 輪郭情報をndarrayに変換
たぶんndarrayの形が汚い(3*3,4*4などになっていない)というエラーだと思いますが、あまり自信を持てません。Pythonのヴァージョンアップにより、新たに生じたエラーだと思いますが、修正方法がわからず困っています。
もしお時間あれば、ご対応ないし教えていただければうれしいです。
ご訪問ありがとうございます。
こちらではPython3.9.6、PyCharmで実行して特にエラーが発生しませんでした(Macbookで確認)。
エラーの内容から、14行目を
contours = np.array(contours, dtype=’int32′)
と変更するなどはいかがでしょうか?
また、本記事「サンプル動画」の部分に僕が使った動画へのダウンロードボタンを設置してみました。
Pythonのバージョン情報を記載してみましたが、何かヒントになるでしょうか?
こちらではエラーが出なかったので、使っている動画が合っていないのか、コンピュータ、実行環境、ライブラリのバージョン…等が要因ではないかと思いました。
以上、よろしくお願い致します。
物体が途中で見切れてしまっているような映像だとこの方法で速度や加速度を求めるのは難しいですよね?
ご訪問ありがとうございます。
はい。
見切れていたり、ノイズが激しかったりといった場合には別の手段、追加アルゴリズム、例外処理等を検討する必要があると思います。
質問させてください。
こちらのコードを引用してファイルを作成したのですが、作成されたファイルのサイズが0KBとなっており、再生しようとするとエラーが発生します。
Pycharm上はエラーが発生していないのですが、どのように改善すればよいのでしょうか?
よろしくお願いいたします。
申し訳ありません。コードを書き換えると上手く保存できました。ただトラッキングは上手くできていないので、また相談させてください。
よろしくお願いいたします。
ご訪問ありがとうございます。
保存に関して解決されたようでよかったです。
トラッキングは全てのケースでうまくいくアルゴリズムというのは難しいかも知れません。
この記事では輪郭情報を使っていますが、テンプレートマッチングのような方法もあります↓
https://watlab-blog.com/2021/02/04/pattern-match-tracking/
是非色々な方法を試してみてください。
動画が再生できない場合はどうすればよいでしょうか?
ご訪問ありがとうございます。
「動画が再生できない」とは、当ブログでダウンロード可能にしているmp4ファイルが再生できないということでしょうか?
それとも、記事内で紹介しているYouTube動画が再生できないということでしょうか?
こちらの環境では両方正常に再生されていますので、
前者であればmp4の再生環境、後者であればブラウザに問題がないか調べる必要があると思います。
以上、よろしくお願いいたします。
コメント失礼いたします.
すでにコメントされている方もいらっしゃいましたが,こちらのコードを引用してファイルを作成しました.結果,作成されたファイルのサイズが0KBとなり,再生しようとすると「0xc10100be」のエラーが発生します
Pycharm上はエラーが発生していません.改善方法をご教授いただけると幸いです.
よろしくお願いいたします。
ご訪問ありがとうございます。
どうやらこちらの環境では再現しないようです。
先の質問者様は解決されたようなので、もう少し詳しい情報を知ることで解決の可能性があります。
例えば、
・この記事に添付されている動画をダウンロードして、コードをそのまま実行して再生できないのか。
・それとも自前で用意した動画でのみ起こる現象なのか。
・PCでmp4はそもそも再生できるのか(コーデックがあるか)
・Python環境(バージョン等)がこの記事のものと同じか。
記載頂いたエラーは再生時に発生するものとのことで、エラーコードをGoogleで検索すると以下のような記事がヒットしました。
↓0xC10100BEビデオエラーで動画を再生できない場合の対処方法をご紹介!
https://recoverit.wondershare.jp/video-repair/fix-0xc10100be-video-error.html
お使いのPCが動画フォーマットに対応していない可能性があり、mp4以外のエンコードを試すか動画再生ソフトを見直すか…かも知れません。
以上、よろしくお願い致します。
コメント失礼します.
座標のプロットに関してなのですが、
こちらを横軸の単位を時間に変更し、時間に対する変位にする事は可能でしょうか。
もし可能でしたらご教授いただけますと幸いです。
いつもご訪問ありがとうございます。
可能です。
以下のコードでFPS(1秒当たりのフレーム数)でコマ画像が1つ進む時間を取得しています。
fps = int(movie.get(cv2.CAP_PROP_FPS))
つまり横軸にこの情報を使うことで時間に変更することが可能です。
そして縦軸を変位([mm]や[m])にするのは、1ピクセル当たりの長さを考慮することで変換可能です。
通常、商用の画像処理ソフトではキャリブレーションを行って物理単位の長さ情報に変換しています。
スケールやグリッドを使って撮影画角における長さを別途計算するプログラムにすることで変位に変換することができます。
以上、ご検討よろしくお願い致します。
ご回答ありがとうございます。グラフの横軸の値を指定するのはどちらのコードなのでしょうか。
matplotlibで無理やり軸の設定を変更するよりは、抽出した座標値に対して処理を行う方が良いと思います。
x, y = contours(frame)
でx, y座標を計算していますので、この次の行にxとyそれぞれに対して適切な値に校正することで目的のグラフとなります。
または、whileループの外でx_list, y_listに対して一括に校正係数をかける処理をしても良いと思います。
ご回答ありがとうございます。pythonのプログラミングは初めてなのでご教授いただければ幸いです。早速ですが、今回の提案はx, y = contours(frame)で出力した値に校正値を代入してx座標
をfps値に変換するということでしょうか。もしくはx, y = contours(frame)はそのままに新たな関数を導入した方がよいでしょうか。
すみません、こちらの方で勘違いしていました。
本処理は2次元の画像の処理でしたので、x, yは共に変位に変換することができますが、時間にすることはできません。
変位への変換は
x, y = contours(frame) * 校正係数
で良いと思いますが、横軸を時間にするというのは、今回のx,yの変位にさらに軸を追加して3次元グラフを作りたいということでしょうか?
例えば、横軸となる時間波形を新たにnp.linspaceやnp.arangeで作り、x,yの変位をz=np.sqrt(x**2 + y**2)等でひとまとめにするという案もあります。
2次元の位置情報を時間とどう関連付けたいか、という部分があれば色々やりようがありそうです。
最初勘違いしており申し訳ございませんでしたが、ご検討お願いします。
ご回答ありがとうございます。私が作成したいのは横軸が時間で縦軸が変位のグラフです。
時間はfpsから求めることが出来るとご教授いただきましたが、そちらの情報をどこに挿入すればグラフの横軸を時間に変更できるかが理解できていません。球の減衰の様子をこちらのプログラムを応用して計測したいと考えています。
なるほど球の減衰ですか、何となくですがイメージできました。
例えば反発する球の振動をトラッキングして後ほど減衰カーブにフィットさせ、減衰率を計算する…ようなことをイメージして
「おまけ3」を記事に追加してみました。
このようなコードで時間軸に対する挙動を分析することが可能です。
ただ、縦軸変位に変換するためには、1ピクセルが何mmなのかといった情報を別途x_list, y_listに考慮してあげることが必要です。
失礼します。
OpenCV: Couldn’t read video stream from file “video.mp4”
のエラーコードが出て解決策がわかりません。今video.mp4はデスクトップに置いています。ご教授願います。
エディタはvscordを使用しています。
ご訪問ありがとうございます。
そのエラーはファイルパスが見つからない時にでてくるようです。
動画読み込み部分「# 動画読み込み」の前に以下のコードを書いて実行してみてください。
ファイルパスが存在するとTrue, 存在しないとFalseになります。
# Debug
print(“file exists?”, os.path.exists(filename))
もしFalseが出る場合、おそらくデスクトップにファイルを置いていることが原因と思います。
その場合は.pyファイルと同じ場所に動画ファイルを置いてみてください。
以上、よろしくお願い致します。
質問です。
本記事では、動画ファイルからベクトル軌跡を描いていると思いますが、カメラの映像を取り込みベクトル軌跡を描くことは可能でしょうか?(カメラ映像は決められた動きではない)
また可能であれば、どのような方法が適切で、やり方まで教えていただけると幸いです。
*僕の悩んだポイント*
x = np.mean(contours[0].T[0, 0]) # 輪郭のx方向平均値を算出
のT[0,0]って[[]]になるからわざわざ[0,0]おいている。