LoginSignup
17
18

More than 5 years have passed since last update.

バスケットボールの動画解析に挑戦するためのメモ

Last updated at Posted at 2016-09-22

http://qiita.com/northriver/items/d6b73da79a13bf3526e2
opencvについてわかってきたので、表題に向けて、チャレンジしてみる

まずは、参考になりそうなものを使って、理解する
※まだ完成しておりません、勉強している仮定でのメモになります

緑のボールをトラッキングしているコードを見つけたので、やってみる。これは色で検知しているみたい
http://www.pyimagesearch.com/2015/09/14/ball-tracking-with-opencv/

# 必要なパッケージをインポート
from collections import deque
import numpy as np
import argparse
import imutils
import cv2
# 実行する際の引数を作る。「python xxx.py -v test.mov」の-vのこと
ap = argparse.ArgumentParser()
ap.add_argument("-v", "--video",help="path to the (optional) video file")
ap.add_argument("-b", "--buffer", type=int, default=64,help="max buffer size")
args = vars(ap.parse_args())

argparse の説明はこちら http://python.civic-apps.com/argparse/

# 追っかけるボールの色を定義 "green" (HSV)
greenLower = (29, 86, 6)
greenUpper = (64, 255, 255)
pts = deque(maxlen=args["buffer"])

HSV色空間 http://www.peko-step.com/html/hsv.html

# 引数があったらそのファイルのパス、なかった時は、webcamに
if not args.get("video", False):
    camera = cv2.VideoCapture(0)
else:
    camera = cv2.VideoCapture(args["video"])
while True:
    # カメラ、動画撮りこむ
    (grabbed, frame) = camera.read()

    # できなかたら、break
    if args.get("video") and not grabbed:
        break

    # resize
    frame = imutils.resize(frame, width=600)
    # hsvに変換
    hsv = cv2.cvtColor(frame, cv2.COLOR_BGR2HSV)
    # 緑のところだけを抜き出し、モルフォロジー変換を行う
    mask = cv2.inRange(hsv, greenLower, greenUpper)
    mask = cv2.erode(mask, None, iterations=2)
    mask = cv2.dilate(mask, None, iterations=2)

モルフォロジー変換をしている。モルフォロジー変換は,物体の特徴的な部分を抽出し,それ以外を削
減するということをしています。cv2.erodeは収縮(Erosion)させて特徴的な部分を残し、cv2.dilate膨張(Dilation)をさせて、大事なところだけを元に戻しているということをしている
http://labs.eecs.tottori-u.ac.jp/sd/Member/oyamada/OpenCV/html/py_tutorials/py_imgproc/py_morphological_ops/py_morphological_ops.html

    # 2値の白黒データから輪郭を抽出
    # (x, y) center of the ball
    cnts = cv2.findContours(mask.copy(), cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_SIMPLE)[-2]
    center = None

cv2.findContoursで2値の白黒データから輪郭を抽出する。RETR_EXTERNALは最も外側だけを抽出するモード、CHAIN_APPROX_SIMPLEは輪郭の近似手法のやり方
http://opencv.jp/opencv-2.1/cpp/structural_analysis_and_shape_descriptors.html

    if len(cnts) > 0:
        # 領域が占める面積を計算視、面積が最大のものを見つける
        c = max(cnts, key=cv2.contourArea)
        #最小の円を見つける
        ((x, y), radius) = cv2.minEnclosingCircle(c)
    #モーメント(面積や重心などの基礎数値)を計算すし、円の中心の座標を出す
        M = cv2.moments(c)
        center = (int(M["m10"] / M["m00"]), int(M["m01"] / M["m00"]))

        # 円を描く
        if radius > 10:
            cv2.circle(frame, (int(x), int(y)), int(radius),
(0, 255, 255), 2)
            cv2.circle(frame, center, 5, (0, 0, 255), -1)

以下は、軌道を後追いで描くのにあるので、なくても大丈夫

    # update the points queue
    pts.appendleft(center)
    # loop over the set of tracked points
    for i in xrange(1, len(pts)):
        # if either of the tracked points are None, ignore
        # them
        if pts[i - 1] is None or pts[i] is None:
            continue

        # otherwise, compute the thickness of the line and
        # draw the connecting lines
        thickness = int(np.sqrt(args["buffer"] / float(i + 1)) * 2.5)
        cv2.line(frame, pts[i - 1], pts[i], (0, 0, 255), thickness)

あとはアウトプットするだけ、こちらはチュートリアルと同じ

    # show the frame to our screen
    cv2.imshow("Frame", frame)
    key = cv2.waitKey(1) & 0xFF

    # if the 'q' key is pressed, stop the loop
    if key == ord("q"):
        break

# cleanup the camera and close any open windows
camera.release()
cv2.destroyAllWindows()

最初から最後まで繋げる

# import the necessary packages
from collections import deque
import numpy as np
import argparse
import imutils
import cv2

# construct the argument parse and parse the arguments
ap = argparse.ArgumentParser()
ap.add_argument("-v", "--video",
    help="path to the (optional) video file")
ap.add_argument("-b", "--buffer", type=int, default=64,
    help="max buffer size")
args = vars(ap.parse_args())

# define the lower and upper boundaries of the "green"
# ball in the HSV color space, then initialize the
# list of tracked points
greenLower = (29, 86, 6)
greenUpper = (64, 255, 255)
pts = deque(maxlen=args["buffer"])

# if a video path was not supplied, grab the reference
# to the webcam
if not args.get("video", False):
    camera = cv2.VideoCapture(0)

# otherwise, grab a reference to the video file
else:
    camera = cv2.VideoCapture(args["video"])

# keep looping
while True:
    # grab the current frame
    (grabbed, frame) = camera.read()

    # if we are viewing a video and we did not grab a frame,
    # then we have reached the end of the video
    if args.get("video") and not grabbed:
        break

    # resize the frame, blur it, and convert it to the HSV
    # color space
    frame = imutils.resize(frame, width=600)
    # blurred = cv2.GaussianBlur(frame, (11, 11), 0)
    hsv = cv2.cvtColor(frame, cv2.COLOR_BGR2HSV)

    # construct a mask for the color "green", then perform
    # a series of dilations and erosions to remove any small
    # blobs left in the mask
    mask = cv2.inRange(hsv, greenLower, greenUpper)
    mask = cv2.erode(mask, None, iterations=2)
    mask = cv2.dilate(mask, None, iterations=2)
    # find contours in the mask and initialize the current
    # (x, y) center of the ball
    cnts = cv2.findContours(mask.copy(), cv2.RETR_EXTERNAL,
        cv2.CHAIN_APPROX_SIMPLE)[-2]
    center = None

    # only proceed if at least one contour was found
    if len(cnts) > 0:
        # find the largest contour in the mask, then use
        # it to compute the minimum enclosing circle and
        # centroid
        c = max(cnts, key=cv2.contourArea)
        ((x, y), radius) = cv2.minEnclosingCircle(c)
        M = cv2.moments(c)
        center = (int(M["m10"] / M["m00"]), int(M["m01"] / M["m00"]))

        # only proceed if the radius meets a minimum size
        if radius > 10:
            # draw the circle and centroid on the frame,
            # then update the list of tracked points
            cv2.circle(frame, (int(x), int(y)), int(radius),
                (0, 255, 255), 2)
            cv2.circle(frame, center, 5, (0, 0, 255), -1)

    # update the points queue
    pts.appendleft(center)
    # loop over the set of tracked points
    for i in xrange(1, len(pts)):
        # if either of the tracked points are None, ignore
        # them
        if pts[i - 1] is None or pts[i] is None:
            continue

        # otherwise, compute the thickness of the line and
        # draw the connecting lines
        thickness = int(np.sqrt(args["buffer"] / float(i + 1)) * 2.5)
        cv2.line(frame, pts[i - 1], pts[i], (0, 0, 255), thickness)

    # show the frame to our screen
    cv2.imshow("Frame", frame)
    key = cv2.waitKey(1) & 0xFF

    # if the 'q' key is pressed, stop the loop
    if key == ord("q"):
        break

# cleanup the camera and close any open windows
camera.release()
cv2.destroyAllWindows()

さて、ここまでやってみたが、いざバスケの動画を入れると、検知できず、、、色的な問題がある

greenLower = (7,100,100)
greenUpper = (11,255,255)

バスケの場合、ボールが体育館と近い色だし、古いボールは黒だったりする。なので、認識方法を色検知以外でやる必要がある。

http://labs.eecs.tottori-u.ac.jp/sd/Member/oyamada/OpenCV/html/py_tutorials/py_video/py_table_of_contents_video/py_table_of_contents_video.html#py-table-of-content-video
改良版も見つけた
http://answers.opencv.org/question/17637/backgroundsubtractormog-with-python/
一応上記、背景差分で動体検知をする方法もあるので、試してみたが、バスケの場合カメラが動くので、背景がない、、、微妙、、、、

良いアイディアが思いつかない、、、
もし、こうしたら良いとかありましたら教えてください。

これ?
http://qiita.com/olympic2020/items/3d8973f855e963c9d999

やってみたが、ダメだった、、、

17
18
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
17
18