QA@IT

python-OpenCVによるハフ変換と時間計測について

383 PV

現在、webカメラによりリアルタイムでハフ変換を行い円を検出、座標により円を区別しそれぞれの円の出現時間を計測するプログラムを作成しています。以下がプログラムコードです。

from datetime import datetime
import math
import numpy as np
import cv2

FIND_DIST = 30 
targets = []

id = 1
cap = cv2.VideoCapture(1)
while True:
    pts = []
    now_time = datetime.now()
    ret, frame = cap.read()
    gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
    gray = cv2.GaussianBlur(gray, (33,33), 1)
    circles = cv2.HoughCircles(gray, cv2.HOUGH_GRADIENT, 1, 60, param1=10, param2=85, minRadius=10, maxRadius=80)

    if circles is not  None:

        circles = np.uint16(np.around(circles))
        for i in circles[0,:]:
            cv2.circle(frame,(i[0],i[1]),i[2],(255,255,0),2)
            cv2.circle(frame,(i[0],i[1]),2,(0,0,255),3)
            pt = (i[0],i[1])
            pts.append((float(pt[0]), float(pt[1])))

    for tgt in targets:
        tgt['bIn'] = False

    new_tgts = []

    for pt in pts:
        bIn = False 
        for tgt in targets:

            if math.sqrt( math.pow(pt[0] - tgt['pos'][0], 2) + math.pow(pt[1] - tgt['pos'][1], 2)) <= FIND_DIST:
                tgt['bIn'] = True
                tgt['pos'] = pt
                bIn = True  #次フレームでも円が見つかった場合、そのをIDをTrueに変更

        if not bIn:    #発見された円の座標をlistに追加、状態をTrueにする             
            new_tgt = {'id':id,'bIn':True,'pos':pt,'in_time':now_time}
            new_tgts.append(new_tgt)
            id += 1

    for tgt in targets:
        if tgt['bIn']:  #リスト内のTrueのIDをnew_tgtsに加えていく
            new_tgts.append(tgt)
        else:         #リスト内にFalseのIDがあった場合円が消えたと認識、時間を出力
            print('{}sec'.format((now_time - tgt['in_time']).total_seconds()))

    targets = new_tgts 


    cv2.imshow('preview', frame) 
    key = cv2.waitKey(10)
    if key == ord("q"):
        break

cv2.destroyAllWindows()
コード

上記のプログラムを実際に動かした結果、円を3枚映し続けていても認識出来ず、消えたと判断されてしまうようことが多々ありました。
そこで、
現フレームで見つからなかった残留点について、bInを0からデクリメントしていく。

途中でまた見つかった場合は失踪時間を0に初期化更新して残留リストにも残しておく。
                  ↓
そして(失踪から)5フレームたったら離脱と認定し、残留リストから外す。
というプログラムに書き換えようと考えました。
自分なりに改良したものが以下のコードです。

from datetime import datetime
import math
import numpy as np
import cv2

FIND_DIST = 30 

targets = []

id = 1
cap = cv2.VideoCapture(1)
while True:
    pts = []
    now_time = datetime.now()
    ret, frame = cap.read()
    gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
    gray = cv2.GaussianBlur(gray, (33,33), 1)
    circles = cv2.HoughCircles(gray, cv2.HOUGH_GRADIENT, 1, 60, param1=10, param2=85, minRadius=10, maxRadius=80)

    if circles is not  None:

        circles = np.uint16(np.around(circles))
        for i in circles[0,:]:
            cv2.circle(frame,(i[0],i[1]),i[2],(255,255,0),2)
            cv2.circle(frame,(i[0],i[1]),2,(0,0,255),3)
            pt = (i[0],i[1])
            pts.append((float(pt[0]), float(pt[1])))


    print(pts)

    new_tgts = []

    for pt in pts:
        bIn = 0
        print("D") 

        if not bIn:
            new_tgt = {'id':id,'bIn':1,'pos':pt,'in_time':now_time}
            new_tgts.append(new_tgt)
            id += 1
            print("a")

        for tgt in targets:
            if math.sqrt( math.pow(pt[0] - tgt['pos'][0], 2) + math.pow(pt[1] - tgt['pos'][1], 2)) <= FIND_DIST:
                tgt['bIn'] = 1
                tgt['pos'] = pt
                bIn = 1
                print("b")

    for tgt in targets:
        if tgt['bIn'] > -5 : 
            new_tgts.append(tgt)
            print("c")

        elif tgt['bIn'] == -5:         
            print('{}sec'.format((now_time - tgt['in_time']).total_seconds()))
            new_tgts = [tgt for tgt in targets if  tgt['bIn'] == 1]



    targets = new_tgts


    for tgt in targets:
        if tgt['bIn'] == 1:
            tgt['bIn'] = 0

        else:
            tgt['bIn'] -= 1

    cv2.imshow('preview', frame) 
    key = cv2.waitKey(10)
    if key == ord("q"):
        break

cv2.destroyAllWindows()  

コード

やりたかったこととしては、円が消えたと判断されたときbInをデクリメント。もし、bInが-5となったら離脱とみなし時間を表示、さらにリスト内のbIn=-5となっている要素を消去するというものです。
実行させた結果が以下の写真となります。

結果
円を画面から外すと数字の羅列があり、その後また初期状態に戻るようです。原因を探ろうとしたのですが、プログラミングを始めて間もないこともあり、突き止めることが出来ませんでした。上記のような症状が出る原因として何が考えられるか教えていただきたいです。

ウォッチ

この質問への回答やコメントをメールでお知らせします。