0
1

More than 3 years have passed since last update.

OpenCV2で物体追跡 〜 特徴点の移動軌跡をlineではなくarrowedLIneに変えてウインドウに動画出力

Last updated at Posted at 2021-08-12

前の記事で取り組んだオプティカル・フローの物体移動軌跡(trajectory)を線(cv2.line)から矢印(cv2.arrwedLine)に変えてみた。

( 前の記事 )

Have changed cv2.line tp cv2.arrowedLine in optical flow drawing script.

( 変更後の出力結果 )

  • 左下の画面を見ると、ところどころ小さな矢印の先(「>」)が見える

( 変更前 )

mask = cv2.line(mask, (int(next_x), int(next_y)), (int(prev_x), int(prev_y)), color[i].tolist(), 2)

( 変更後 )

mask = cv2.arrowedLine(mask, \
    pt1=(int(next_x), int(next_y)), \
    pt2=(int(prev_x), int(prev_y)), \
           color=color[i].tolist(),
           thickness=2,
           line_type=cv2.LINE_4,
           shift=0,
           tipLength=0.5)

変更後のスクリプト・ファイル

import numpy as np
import cv2
import argparse    

# 動画ファイル名をコマンドライン引数から受け取る
parser = argparse.ArgumentParser(description='')    #
parser.add_argument('file_name')  
args = parser.parse_args()  

movie_file = args.file_name
print('次の動画ファイルを解析します。 :' + movie_file)
cap = cv2.VideoCapture(movie_file)

# Shi-Tomasiのコーナー検出パラメータ
feature_params = dict( maxCorners = 100,
                    qualityLevel = 0.3,
                    minDistance = 7,
                    blockSize = 7 )

# Lucas-Kanade法のパラメータ
lk_params = dict( winSize  = (15,15),
                  maxLevel = 2,
                  criteria = (cv2.TERM_CRITERIA_EPS | cv2.TERM_CRITERIA_COUNT, 10, 0.03))

# ランダムに色を100個生成(値0~255の範囲で100行3列のランダムなndarrayを生成)
color = np.random.randint(0, 255, (100, 3))

# 最初のフレームの処理
end_flag, frame = cap.read()
gray_prev = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
feature_prev = cv2.goodFeaturesToTrack(gray_prev, mask = None, **feature_params)
mask = np.zeros_like(frame)

while(end_flag):
    if feature_prev is None:
        print("フレームに追跡すべき特徴点が見つかりませんでした。")
        break

    # グレースケールに変換
    gray_next = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)

    # オプティカルフロー検出
    feature_next, status, err = cv2.calcOpticalFlowPyrLK(gray_prev, gray_next, feature_prev, None, **lk_params)

    # フレーム前後でトラックが成功した特徴点のみを
    if feature_next is None:
        print("フレームに追跡すべき特徴点が見つからなくなりました。")
        break

    # オプティカルフローを検出した特徴点を選別(0:検出せず、1:検出した)
    good_prev = feature_prev[status == 1]
    good_next = feature_next[status == 1]

    # オプティカルフローを描画
    for i, (next_point, prev_point) in enumerate(zip(good_next, good_prev)):
        prev_x, prev_y = prev_point.ravel()
        next_x, next_y = next_point.ravel()
        # cv2.lineをcv2.arrowedLineに変更
        #mask = cv2.line(mask, (int(next_x), int(next_y)), (int(prev_x), int(prev_y)), color[i].tolist(), 2)
        frame = cv2.circle(frame, (int(next_x), int(next_y)), 5, color[i].tolist(), -1)

        mask = cv2.arrowedLine(mask, \
                pt1=(int(next_x), int(next_y)), \
                pt2=(int(prev_x), int(prev_y)), \
                color=color[i].tolist(),
                thickness=2,
                line_type=cv2.LINE_4,
                shift=0,
                tipLength=0.5)

    img = cv2.add(frame, mask)

    # 背景黒の画面。zerosの引数がheightが先になるので注意
    height_ = frame.shape[0]
    width_ = frame.shape[1]
    black_bachground_img = np.zeros((height_, width_, 3),np.uint8)

    # ウィンドウに表示
    #cv2.imshow('window', img)
    #cv2.imshow('window2', frame)
    #cv2.imshow('window3', mask)

    # 4つの画像を1つのウィンドウに組込む
    merged_image_group_1 = cv2.hconcat((frame, img))
    merged_image_group_2 = cv2.hconcat((mask, black_bachground_img))
    height = merged_image_group_1.shape[0]
    width = merged_image_group_1.shape[1]

    resized_output_img_1 = cv2.resize(merged_image_group_1, (int(1.7*width), int(1.7*height)))
    resized_output_img_2 = cv2.resize(merged_image_group_2, (int(1.7*width), int(1.7*height)))
    final_output_image = cv2.vconcat((resized_output_img_1, resized_output_img_2))

    cv2.namedWindow("Video", cv2.WINDOW_NORMAL)
    cv2.imshow("Video", final_output_image)

    # ESCキー押下で終了
    if cv2.waitKey(30) & 0xff == 27:
        break

    # 次のフレーム、ポイントの準備
    gray_prev = gray_next.copy()
    feature_prev = good_next.reshape(-1, 1, 2)
    end_flag, frame = cap.read()

# 終了処理
cv2.destroyAllWindows()
cap.release()
0
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
1