Python cv2.HoughCircles で円検出


Python + Opencv3.1 で Webカメラからの映像での円検出を試してみました。

今回検出で使用した関数での大まかな流れとしては繰り返し処理の中で、

1. カメラをキャプチャしてグレースケールに変換。
2. 平滑化すると認識がよくなるらしいのでガウシアンブラーをかける。
3. 表示用イメージを用意。
4. cv2.HoughCircles で円検出。
5. 円を検出したら表示用イメージに囲み線と中心点を描画
6. プレビュー画像表示

といった感じで、下記が認識部分のコードです。

def hougeCircles():
    while(cam.isOpened()):
    	# カメラのフレームをキャプチャ
        ret, frame = cam.read()
        # ミラー
        frame = frame[:,::-1]
        # 入力画像をリサイズ
        size = (640, 480)
        frame = cv2.resize(frame, size)
        # グレースケール化
        gray = cv2.cvtColor(frame, cv2.COLOR_RGB2GRAY)
        # 認識の精度を上げるために画像を平滑化
        gray = cv2.GaussianBlur(gray, (33,33), 1)

        # 表示用イメージ
        colimg = frame.copy() #cv2.cvtColor(gray, cv2.COLOR_GRAY2BGR)

        # 円検出
        circles = cv2.HoughCircles(gray, cv2.HOUGH_GRADIENT, 1, 60, param1=10, param2=85, minRadius=10, maxRadius=80)
        if circles != None:
            circles = np.uint16(np.around(circles))
            for i in circles[0,:]:
                # 囲み線を描く
                cv2.circle(colimg,(i[0],i[1]),i[2],(255,255,0),2)
                # 中心点を描く
                cv2.circle(colimg,(i[0],i[1]),2,(0,0,255),3)

        # プレビュー
        cv2.imshow('preview', colimg)
        if cv2.waitKey(33) >= 0:
            break

    # ループを抜けたら終了
    cv2.destroyAllWindows()

でもこれ、検出の精度はそこそこいけると思うのですが、カメラのフレームレートが出ないとちょっと残念な感じになってしまうので、実際にこれで何かを作るときは高速な USB3.0 の工業用カメラとか、OptiTrack のようなモーションキャプチャ用のカメラを使用したほうがいいかもしれませんね。

—– 12月2日 追記 —–

カメラのフレームレートが遅いせいでの認識外れが少なくなるように、上記 Python のコードを C++ で書き直して、カメラに RealSense の赤外線ストリーム(最大 60fps)を使用してテストしてみたところ、結構いい感じで認識するようになりました。