Python+OpenCVのカラートラッキングで振り子の運動を測定する方法をソースコード付きで解説します。
Python+OpenCVで振り子の運動を測定
前回、ブロブ解析+カラートラッキングで物体追跡を行う方法を紹介しました。
【Python/OpenCV】ブロブ解析+カラートラッキングで物体追跡
Python+OpenCVのブロブ解析+カラートラッキングで物体追跡する方法をソースコード付きで解説します。
今回は、上記ページのプログラムを応用して、赤色の振り子を色追跡し、その中心座標を記録してグラフ化してみます。
今回解説するプログラムの実行結果
■赤色の振り子を追跡している様子
■グラフ化した結果
グラフの横軸は経過時間[sec]、縦軸は赤色物体の位置座標(x,y)[px]です。
振り子の周期運動を観測できていることがわかります。
サンプルコード①赤色の振り子を追跡し、中心座標を記録
赤色の振り子を追跡し、中心座標をテキストファイル(data.txt)に記録するサンプルプログラムのソースコードです。
サンプルコード②記録データをグラフ化
記録データ(data.txt)をグラフ化するサンプルプログラムのソースコードです。
サンプルコード①の詳細解説
サンプルコード①のの各部分を詳しく解説します。
インポートと初期設定
import cv2
import numpy import time
cv2
: OpenCVライブラリを使用して画像処理を行います。OpenCVはコンピュータビジョンのための強力なツールです。np
: NumPyライブラリを使用して数値計算を行います。NumPyは配列操作や数値計算に便利です。time
: 時間計測を行います。プログラムの実行時間を取得し、座標と一緒に記録するために使用します。
赤色検出関数
def red_detect(img):
hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)
hsv_min = np.array([0,127,0])
hsv_max = np.array([30,255,255])
mask1 = cv2.inRange(hsv, hsv_min, hsv_max)
hsv_min = np.array([150,127,0])
hsv_max = np.array([179,255,255])
mask2 = cv2.inRange(hsv, hsv_min, hsv_max)
return mask1 + mask2
- HSV色空間への変換:
cv2.cvtColor(img, cv2.COLOR_BGR2HSV)
は、BGR色空間からHSV色空間に画像を変換します。HSV色空間は色相(Hue)、彩度(Saturation)、明度(Value)で色を表現します。
- 赤色の範囲を定義:
hsv_min
とhsv_max
は赤色の範囲を定義します。赤色は2つの範囲(0-30度と150-179度)で表現されます。
- マスクの作成:
cv2.inRange(hsv, hsv_min, hsv_max)
は、指定した範囲内のピクセルを白(255)、それ以外を黒(0)にするマスクを作成します。
- マスクの合成:
mask1 + mask2
で2つのマスクを合成し、最終的な赤色検出マスクを作成します。
ブロブ解析関数
def analysis_blob(binary_img):
label = cv2.connectedComponentsWithStats(binary_img)
n = label[0] - 1
data = np.delete(label[2], 0, 0)
center = np.delete(label[3], 0, 0)
max_index = np.argmax(data[:, 4])
maxblob = {}
maxblob["upper_left"] = (data[:, 0][max_index], data[:, 1][max_index])
maxblob["width"] = data[:, 2][max_index]
maxblob["height"] = data[:, 3][max_index]
maxblob["area"] = data[:, 4][max_index]
maxblob["center"] = center[max_index]
return maxblob
- ラベリング処理:
cv2.connectedComponentsWithStats(binary_img)
は、2値画像の連結成分(ブロブ)をラベリングし、各ブロブの統計情報を取得します。
- 不要なデータの削除:
np.delete(label[2], 0, 0)
とnp.delete(label[3], 0, 0)
で背景のラベルを削除します。
- 最大ブロブの検出:
np.argmax(data[:, 4])
で面積が最大のブロブのインデックスを取得します。
- 最大ブロブの情報取得:
- 最大ブロブの左上座標、幅、高さ、面積、中心座標を取得し、
maxblob
辞書に格納します。
- 最大ブロブの左上座標、幅、高さ、面積、中心座標を取得し、
メイン関数
def main():
data = []
videofile_path = "C:/github/sample/python/opencv/video/color_tracking/red_pendulum.mp4"
csvfile_path = "C:/github/sample/python/opencv/video/color_tracking/data.csv"
cap = cv2.VideoCapture(videofile_path)
start = time.time()
while(cap.isOpened()):
ret, frame = cap.read()
mask = red_detect(frame)
target = analysis_blob(mask)
center_x = int(target["center"][0])
center_y = int(target["center"][1])
cv2.circle(frame, (center_x, center_y), 30, (0, 200, 0), thickness=3, lineType=cv2.LINE_AA)
data.append([time.time() - start, center_x, center_y])
cv2.imshow("Frame", frame)
cv2.imshow("Mask", mask)
if cv2.waitKey(25) & 0xFF == ord('q'):
break
np.savetxt(csvfile_path, np.array(data), delimiter=",")
cap.release()
cv2.destroyAllWindows()
- データ格納用リストの初期化:
data = []
で追跡データを格納するリストを初期化します。
- 動画ファイルとCSVファイルのパス設定:
videofile_path
とcsvfile_path
で動画ファイルとCSVファイルのパスを設定します。
- 動画キャプチャの開始:
cv2.VideoCapture(videofile_path)
で動画ファイルを読み込みます。
- 開始時間の記録:
start = time.time()
でプログラムの開始時間を記録します。
- フレームごとの処理:
while(cap.isOpened())
で動画が終了するまでフレームを読み込みます。ret, frame = cap.read()
でフレームを取得します。mask = red_detect(frame)
で赤色物体を検出します。target = analysis_blob(mask)
で最大ブロブの情報を取得します。center_x
とcenter_y
でブロブの中心座標を取得します。cv2.circle(frame, (center_x, center_y), 30, (0, 200, 0), thickness=3, lineType=cv2.LINE_AA)
でフレームに円を描画します。data.append([time.time() - start, center_x, center_y])
で経過時間と中心座標をリストに追加します。cv2.imshow("Frame", frame)
とcv2.imshow("Mask", mask)
でフレームとマスクを表示します。if cv2.waitKey(25) & 0xFF == ord('q')
で’q’キーが押されたらループを終了します。
- データの保存とリソースの解放:
np.savetxt(csvfile_path, np.array(data), delimiter=",")
でデータをCSVファイルに保存します。cap.release()
でキャプチャを解放し、cv2.destroyAllWindows()
でウィンドウを閉じます。
サンプルコード②の詳細解説
サンプルコード②は、サンプルコード①で記録した赤色物体の動きをCSVファイルから読み込み、時間に対するx座標とy座標の変化をグラフにプロットするものです。
以下に各部分の詳細な解説をします。
インポートと初期設定
import numpy as np
import matplotlib.pyplot as plt
numpy
: 数値計算ライブラリで、配列操作や数値計算に使用します。matplotlib.pyplot
: グラフ描画ライブラリで、データの可視化に使用します。
メイン関数
def main():
data = np.genfromtxt("/Users/github/sample/python/opencv/video/color_tracking/data.csv", delimiter=",", dtype='float')
np.genfromtxt
: CSVファイルを読み込み、NumPy配列としてデータを取得します。delimiter=","
はカンマ区切りを指定し、dtype='float'
はデータ型を浮動小数点数に指定します。
データの分割
t = data[:,0]
x = data[:,1]
y = data[:,2]
data[:,0]
: 経過時間のデータを取得します。data[:,1]
: x座標のデータを取得します。data[:,2]
: y座標のデータを取得します。
グラフのプロット
plt.rcParams["font.family"] = "Times New Roman"
plt.plot(t, x, "r-", label="x")
plt.plot(t, y, "b-", label="y")
plt.xlabel("Time[sec]", fontsize=16)
plt.ylabel("Position[px]", fontsize=16)
plt.grid()
plt.legend(loc=1, fontsize=16)
plt.show()
- フォントの設定:
plt.rcParams["font.family"] = "Times New Roman"
でグラフのフォントをTimes New Romanに設定します。
- データのプロット:
plt.plot(t, x, "r-", label="x")
で経過時間に対するx座標を赤色の線でプロットします。plt.plot(t, y, "b-", label="y")
で経過時間に対するy座標を青色の線でプロットします。
- 軸ラベルの設定:
plt.xlabel("Time[sec]", fontsize=16)
でx軸のラベルを設定します。plt.ylabel("Position[px]", fontsize=16)
でy軸のラベルを設定します。
- グリッドの表示:
plt.grid()
でグラフにグリッドを表示します。
- 凡例の表示:
plt.legend(loc=1, fontsize=16)
で凡例を表示します。loc=1
は凡例の位置を右上に設定します。
- グラフの表示:
plt.show()
でグラフを表示します。
プログラムの実行
if __name__ == "__main__":
main()
- この部分は、スクリプトが直接実行された場合に
main()
関数を呼び出します。
関連ページ
【Python版OpenCV超入門】使い方とサンプルコードを解説
Python版OpenCVで画像処理プログラミングを行う方法を入門者向けにソースコード付きで解説するページです。
【画像処理入門】アルゴリズム&プログラミング
画像処理における基本的なアルゴリズムとその実装例(プログラム)についてまとめました。
コメント