この記事では、Python版OpenCVで色追跡を実装し、振り子の運動を観測・記録する方法をソースコード付きで解説します。
Webカメラで物体の運動を観測
前回の記事では、HSV色空間を使って色追跡(カラートラッキング)してみました。
| – | 参考記事 |
|---|---|
| 1 | 【Python/OpenCV】カラートラッキング(色追跡)で移動物体の検出 |
| 2 | 【Python/OpenCV】最大面積のブロブ解析 |
今回は、これを応用して、Python+OpenCVでWebカメラを固定して運動物体の座標を観測・記録してみました。
ソースコード(Python3+OpenCV3)
サンプルプログラムのソースコードです。
Webカメラで観測
# -*- coding: utf-8 -*-
import cv2
import numpy as np
import time
def color_tracking(img):
# HSV色空間に変換
hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)
# 赤色のHSVの値域1
hsv_min = np.array([0,100,0])
hsv_max = np.array([60,255,255])
mask1 = cv2.inRange(hsv, hsv_min, hsv_max)
# 赤色のHSVの値域2
hsv_min = np.array([160,100,0])
hsv_max = np.array([255,255,255])
mask2 = cv2.inRange(hsv, hsv_min, hsv_max)
# 2つのマスク画像を加算
mask = mask1 + mask2
# 膨張・収縮処理でノイズ低減
kernel = np.ones((6, 6), np.uint8)
mask = cv2.dilate(mask, kernel)
mask = cv2.erode(mask, kernel)
return mask
def calc_max_point(mask):
if np.count_nonzero(mask) <= 0:
return(-20, -20)
# ラベリング処理
label = cv2.connectedComponentsWithStats(mask)
# ブロブ情報を項目別に抽出
n = label[0] - 1
data = np.delete(label[2], 0, 0)
center = np.delete(label[3], 0, 0)
# ブロブ面積が最大のインデックス
max_index = np.argmax(data[:,4])
# 最大面積をもつブロブの中心座標を返す
return center[max_index]
def main():
# データ格納用のリスト
data = []
# カメラのキャプチャ
cap = cv2.VideoCapture(0)
# 開始時間
start = time.time()
while(cap.isOpened()):
# フレームを取得
ret, frame = cap.read()
# カラートラッキング(赤色)
mask = color_tracking(frame)
# 面積最大ブロブの中心座標(x, y)を取得
x, y = calc_max_point(mask)
# 経過時間, x, yをリストに追加
data.append([time.time() - start, x, y])
# 中心座標に赤丸を描く
cv2.circle(frame, (int(x), int(y)), 20, (0, 0, 255), 10)
# ウィンドウ表示
cv2.imshow("Frame", frame)
cv2.imshow("Mask", mask)
# qキーが押されたら途中終了
if cv2.waitKey(25) & 0xFF == ord('q'):
break
# CSVファイルに保存
np.savetxt("data.csv", np.array(data), delimiter=",")
# キャプチャ解放・ウィンドウ廃棄
cap.release()
cv2.destroyAllWindows()
if __name__ == '__main__':
main()
記録データをグラフ化
# -*- coding: utf-8
import numpy as np
import matplotlib.pyplot as plt
def main():
# CSVのロード
data = np.genfromtxt("data.csv",delimiter=",", dtype='float')
# 2次元配列を分割(経過時間t, x座標, y座標の1次元配列)
t = data[:,0]
x = data[:,1]
y = data[:,2]
# グラフにプロット
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) # x軸ラベル
plt.ylabel("Position[px]", fontsize=16) # y軸ラベル
plt.grid() # グリッド表示
plt.legend(loc=1, fontsize=16) # 凡例表示
plt.show()
if __name__ == "__main__":
main()
実行結果
サンプルプログラムの実行結果です。
■カメラ映像
■グラフ化

グラフの横軸は経過時間[sec]、縦軸は赤色物体の位置座標
[px]です。
振り子の周期運動を観測できていることがわかります。
| - | 関連記事 |
|---|---|
| 1 | PythonでOpenCV入門 サンプル集 |
| 2 | 【Python】画像処理プログラミング入門 |
| 3 | 【画像処理入門】アルゴリズム&プログラミング |

コメント
赤色以外を抽出したいのですがHSVの値を変えてもうまくいきません
どうすれば緑色などで、できますか?
※ふくとも様
コメントありがとうございます。
緑系のHSVは
H:60~170[度]
S:50~100%
V:0~100%
となりますので、OpenCVのスケールに合わせて
H:30~90
S:128~255
V:0~255
辺りなら抽出できるかと思います。
参考:【画像処理】HSV色空間とカラートラッキングによる物体追跡の原理
https://python.joho.info/image-processing/hsv-color-tracking/