4
1

More than 3 years have passed since last update.

【 OpenCV2 】物体追跡コードのエラー対処法 〜 line, circleの引数はint型、特徴点未検出のフレームは飛ばす

Last updated at Posted at 2021-07-18

OpenCV2のオブジェクト・トラッキングに関する記事です。

ウェブサイトに公開されている実装コードに、任意の動画ファイルを食わせたところ、複数の公開コード共通する「コードの修正ポイント」を見つけました。

原因と解決策について、検討がついたので、知見を共有したいと思います。

サンプルコードの例

(直面したエラー1)

Terminal
Traceback (most recent call last):
  File "/Users/electron/Desktop/optical_flow/optical_flow.py", line 72, in <module>
    mask = cv2.line(mask, (p1_x, p1_y), (p0_x, p0_y), color[i].tolist(), 2)
cv2.error: OpenCV(4.5.3) :-1: error: (-5:Bad argument) in function 'line'
> Overload resolution failed:
>  - Can't parse 'pt1'. Sequence item with index 0 has a wrong type
>  - Can't parse 'pt1'. Sequence item with index 0 has a wrong type
Terminal
Traceback (most recent call last):
  File "/Users/electron/Desktop/optical_flow/optical_flow.py", line 74, in <module>
    frame = cv2.circle(frame, (p1_x, p1_y), 5, color[i].tolist(), -1)
cv2.error: OpenCV(4.5.3) :-1: error: (-5:Bad argument) in function 'circle'
> Overload resolution failed:
>  - Can't parse 'center'. Sequence item with index 0 has a wrong type
>  - Can't parse 'center'. Sequence item with index 0 has a wrong type

(解決策1)

cv2.lineメソッドとcv2.circleメソッドの引数は、int型である必要がある。
この制約を満たすために、座標点が整数値(integer)になるように、int()で型変換する。

修正前
        mask = cv2.line(mask, (next_x, next_y), (prev_x, prev_y), color[i].tolist(), 2)
        frame = cv2.circle(frame, (next_x, next_y), 5, color[i].tolist(), -1)
修正後
        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)

(直面したエラー2)

オブジェクトがemptyであるエラー

Terminal
Traceback (most recent call last):
  File "/Users/electron/Desktop/optical_flow/trial.py", line 22, in <module>
    gray_prev = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
cv2.error: OpenCV(4.5.3) /private/var/folders/24/8k48jl6d249_n_qfxwsl6xvm0000gn/T/pip-req-build-2id2kgtb/opencv/modules/imgproc/src/color.cpp:182: error: (-215:Assertion failed) !_src.empty() in function 'cvtColor'

新たに読み込んだコマのフレームに、OpenCV2が特徴点を見つけられなかった際に、特徴点オブジェクトがNoneになるために発生する。

(解決策2)

次のif文を挿入する。

Python3挿入コード
    # フレーム前後でトラックが成功した特徴点のみを
    if (p1 is None) or (p0 is None) :
        print("フレームに追跡すべき特徴点が見つからなくなりました。")
        break
修正前
    # グレースケールにしてコーナ特徴点を抽出
prev_gray = cv2.cvtColor(prev_frame, cv2.COLOR_RGB2GRAY)

feature_params = {
    "maxCorners": 200,  # 特徴点の上限数
    "qualityLevel": 0.2,  # 閾値 (高いほど特徴点数は減る)
    "minDistance": 12,  # 特徴点間の距離 (近すぎる点は除外)
    "blockSize": 12  # 
}
p0 = cv2.goodFeaturesToTrack(prev_gray, mask=None, **feature_params)

  ・・・途中省略 ・・・)

    # OpticalFlowの計算
    p1, status, err = cv2.calcOpticalFlowPyrLK(prev_gray, frame_gray, p0, None, **lk_params)

    identical_p1 = p1[status==1]
    identical_p0 = p0[status==1]
修正後
    # グレースケールにしてコーナ特徴点を抽出
prev_gray = cv2.cvtColor(prev_frame, cv2.COLOR_RGB2GRAY)

feature_params = {
    "maxCorners": 200,  # 特徴点の上限数
    "qualityLevel": 0.2,  # 閾値 (高いほど特徴点数は減る)
    "minDistance": 12,  # 特徴点間の距離 (近すぎる点は除外)
    "blockSize": 12  # 
}
p0 = cv2.goodFeaturesToTrack(prev_gray, mask=None, **feature_params)

  ・・・途中省略 ・・・)

    # OpticalFlowの計算
    p1, status, err = cv2.calcOpticalFlowPyrLK(prev_gray, frame_gray, p0, None, **lk_params)

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

    identical_p1 = p1[status==1]
    identical_p0 = p0[status==1]

エラー回避できるコード

次のコードを参考にしました。

new_opt.py
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()
        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)

    img = cv2.add(frame, mask)

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

    # 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()

実行結果

Terminal
electron@diynoMacBook-Pro optical_flow % python3 new_opt.py dance.mp4                             
次の動画ファイルを解析します。 :dance.mp4
^Z
zsh: suspended  python3 new_opt.py dance.mp4
electron@diynoMacBook-Pro optical_flow % exit

スクリーンショット 2021-07-18 14.56.44.png

( 約1秒経過後 )

スクリーンショット 2021-07-18 14.56.57.png

( 約10秒経過後 )

スクリーンショット 2021-07-18 14.57.34.png

使った動画ファイル(MP4)

Terminal
electron@diynoMacBook-Pro % youtube-dl -F https://youtu.be/T0valuAksuo                    
[youtube] T0valuAksuo: Downloading webpage
[info] Available formats for T0valuAksuo:
format code  extension  resolution note
249          webm       audio only tiny   52k , webm_dash container, opus @ 52k (48000Hz), 1.29MiB
250          webm       audio only tiny   68k , webm_dash container, opus @ 68k (48000Hz), 1.70MiB
140          m4a        audio only tiny  129k , m4a_dash container, mp4a.40.2@129k (44100Hz), 3.20MiB
251          webm       audio only tiny  134k , webm_dash container, opus @134k (48000Hz), 3.33MiB
394          mp4        256x144    144p   70k , mp4_dash container, av01.0.00M.08@  70k, 30fps, video only, 1.74MiB
278          webm       256x144    144p   92k , webm_dash container, vp9@  92k, 30fps, video only, 2.28MiB
160          mp4        256x144    144p  104k , mp4_dash container, avc1.4d400c@ 104k, 30fps, video only, 2.59MiB
395          mp4        426x240    240p  153k , mp4_dash container, av01.0.00M.08@ 153k, 30fps, video only, 3.80MiB
242          webm       426x240    240p  216k , webm_dash container, vp9@ 216k, 30fps, video only, 5.34MiB
133          mp4        426x240    240p  243k , mp4_dash container, avc1.4d4015@ 243k, 30fps, video only, 6.01MiB
396          mp4        640x360    360p  329k , mp4_dash container, av01.0.01M.08@ 329k, 30fps, video only, 8.14MiB
243          webm       640x360    360p  396k , webm_dash container, vp9@ 396k, 30fps, video only, 9.80MiB
134          mp4        640x360    360p  588k , mp4_dash container, avc1.4d401e@ 588k, 30fps, video only, 14.53MiB
397          mp4        854x480    480p  611k , mp4_dash container, av01.0.04M.08@ 611k, 30fps, video only, 15.10MiB
244          webm       854x480    480p  734k , webm_dash container, vp9@ 734k, 30fps, video only, 18.14MiB
135          mp4        854x480    480p 1007k , mp4_dash container, avc1.4d401f@1007k, 30fps, video only, 24.88MiB
398          mp4        1280x720   720p 1246k , mp4_dash container, av01.0.05M.08@1246k, 30fps, video only, 30.80MiB
247          webm       1280x720   720p 1472k , webm_dash container, vp9@1472k, 30fps, video only, 36.38MiB
136          mp4        1280x720   720p 1963k , mp4_dash container, avc1.4d401f@1963k, 30fps, video only, 48.49MiB
399          mp4        1920x1080  1080p 2326k , mp4_dash container, av01.0.08M.08@2326k, 30fps, video only, 57.47MiB
248          webm       1920x1080  1080p 2588k , webm_dash container, vp9@2588k, 30fps, video only, 63.92MiB
137          mp4        1920x1080  1080p 4141k , mp4_dash container, avc1.640028@4141k, 30fps, video only, 102.30MiB
18           mp4        640x360    360p  742k , avc1.42001E, 30fps, mp4a.40.2 (44100Hz), 18.35MiB (best)
electron@diynoMacBook-Pro optical_flow % 
Terminal
electron@diynoMacBook-Pro optical_flow % youtube-dl -f18 -o dance.mp4 https://youtu.be/T0valuAksuo
[youtube] T0valuAksuo: Downloading webpage
[download] Destination: dance.mp4
[download] 100% of 18.35MiB in 00:02
electron@diynoMacBook-Pro optical_flow % ls
768x576.avi     fi.mp4          opt_flow_test.py    test.py         trump.mp4
dance.mp4       new_opt.py      optical_flow.py     trial.py
doraemon.mp4        olynpic.mp4     pedestrian.mp4      trump.avi
electron@diynoMacBook-Pro optical_flow % 
electron@diynoMacBook-Pro optical_flow % python3 new_opt.py dance.mp4                             
次の動画ファイルを解析します。 :dance.mp4
^Z
zsh: suspended  python3 new_opt.py dance.mp4
electron@diynoMacBook-Pro optical_flow % exit
4
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
4
1