前提・実現したいこと
Pythonプログラミング初心者です。
AnacondaのspyderでPythonとOpencvを用いて青い卓球台上での橙色の卓球ボールのラリーを追跡するシステムを作成しております。手法といたしましてはHSV表色系により橙色を指定して追跡するカラートラッキングとフレーム間差分を用いて追跡を試みたいと考えております。
手順といたしましては、
1、卓球の動画を読み込む
2、前フレームと後フレームの差分画像を作成
3、差分画像から橙色の物体を検知し、追跡する
という手順です。
発生している問題・エラーメッセージ
まず試しに、橙色を指定したカラートラッキングのみでの追跡、フレーム間差分のみでの追跡それぞれ各自でプログラムを組んで実行したら、エラーが出ずに正常に動かすことができたのですが、どちらの追跡もまだまだノイズが多い状況です。そこで自分なりに試行錯誤してカラートラッキングとフレーム間差分の二つのプログラムを合体させて実行しようと試みているのですが、なかなかうまくいきません。
大変困っている状況です。下の二つのプログラムをどのように組み合わせればうまくいくのかアドバイス頂けると非常に幸いです。
エラーメッセージ
該当のソースコード
Python
# フレーム間差分のプログラム import cv2 import sys import numpy as np def dilation(dilationSize, kernelSize, img): # 膨張した画像にして返す kernel = np.ones((kernelSize, kernelSize), np.uint8) element = cv2.getStructuringElement( cv2.MORPH_RECT, (2 * dilationSize + 1, 2 * dilationSize + 1), (dilationSize, dilationSize)) dilation_img = cv2.dilate(img, kernel, element) return dilation_img def detect(gray_diff, thresh_diff=20, dilationSize=9, kernelSize=20): # 一定面積以上の物体を検出 retval, black_diff = cv2.threshold( gray_diff, thresh_diff, 150, cv2.THRESH_BINARY) # 2値化 dilation_img = dilation(dilationSize, kernelSize, black_diff) # 膨張処理 img = dilation_img.copy() contours, hierarchy = cv2.findContours( dilation_img, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE) # 境界線検出 ball_pos = [] for i in range(len(contours)): # 重心位置を計算 count = len(contours[i]) area = cv2.contourArea(contours[i]) # 面積計算 x, y = 0.0, 0.0 for j in range(count): x += contours[i][j][0][0] y += contours[i][j][0][1] x /= count y /= count x = int(x) y = int(y) ball_pos.append([x, y]) return ball_pos, img def displayCircle(image, ballList, thickness=5): for i in range(len(ballList)): x = int(ballList[i][0]) y = int(ballList[i][1]) cv2.circle(image, (x, y), 10, (0, 200, 0), thickness) return image def resizeImage(image, w=2, h=2): height = image.shape[0] width = image.shape[1] resizedImage = cv2.resize(image, (int(width / w), int(height / h))) return resizedImage def blackToColor(bImage): colorImage = np.array((bImage, bImage, bImage)) colorImage = colorImage.transpose(1, 2, 0) return colorImage def run(input_video_path, output_video_path): video = cv2.VideoCapture(input_video_path) # videoファイルを読み込む # fourcc = cv2.VideoWriter_fourcc(*'MJPG') fourcc = cv2.VideoWriter_fourcc('m', 'p', '4', 'v') if not video.isOpened(): # ファイルがオープンできない場合の処理. print("Could not open video") sys.exit() fps = int(video.get(cv2.CAP_PROP_FPS)) vidw = video.get(cv2.CAP_PROP_FRAME_WIDTH) vidh = video.get(cv2.CAP_PROP_FRAME_HEIGHT) out = cv2.VideoWriter(output_video_path, fourcc, fps, (int(vidw), int(vidh))) # 出力先のファイルを開く ok, frame = video.read() # 最初のフレームを読み込む if not ok: print('Cannot read video file') sys.exit() frame_pre = frame.copy() while True: ok, frame = video.read() # フレームを読み込む if not ok: break frame_next = frame.copy() color_diff = cv2.absdiff(frame_next, frame_pre) # フレーム間の差分計算 gray_diff = cv2.cvtColor(color_diff, cv2.COLOR_BGR2GRAY) # グレースケール変換 retval, black_diff = cv2.threshold( gray_diff, 20, 150, cv2.THRESH_BINARY) ball, dilation_img = detect(gray_diff) frame = displayCircle(frame, ball, 2) # 丸で加工 cImage = blackToColor(dilation_img) # 2値化画像をカラーの配列サイズと同じにする cv2.imshow("threshold", cImage) cv2.imshow("Tracking", frame) # フレームを画面表示 out.write(frame) frame_pre = frame_next.copy() # 次のフレームの読み込み k = cv2.waitKey(1) & 0xff # ESCを押したら中止 if k == 27: break video.release() out.release() cv2.destroyAllWindows() if __name__ == '__main__': inputFile="/Users/max/python-opencv/pinpon.mov" outputFile="pinpon.mp4" run(inputFile, outputFile) ----------------------------------------------------- #橙色のカラートラッキングのプログラム import cv2 import numpy as np def orange_detect(img): # HSV色空間に変換 hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV) # オレンジのHSVの値域1 hsv_min = np.array([15,40,170])#動画により値を変更する hsv_max = np.array([16,45,255])#動画により値を変更する mask1 = cv2.inRange(hsv, hsv_min, hsv_max) return mask1 # ブロブ解析 def analysis_blob(binary_img): # 2値画像のラベリング処理 label = cv2.connectedComponentsWithStats(binary_img) # ブロブ情報を項目別に抽出 n = label[0] - 1 data = np.delete(label[2], 0, 0) center = np.delete(label[3], 0, 0) # ブロブ面積最大のインデックス max_index = np.argmax(data[:, 4]) # 面積最大ブロブの情報格納用 maxblob = {} # 面積最大ブロブの各種情報を取得 maxblob["upper_left"] = (data[:, 0][max_index], data[:, 1][max_index]) # 左上座標 maxblob["width"] = data[:, 2][max_index] # 幅 maxblob["height"] = data[:, 3][max_index] # 高さ maxblob["area"] = data[:, 4][max_index] # 面積 maxblob["center"] = center[max_index] # 中心座標 return maxblob def main(): videofile_path = "/Users/max/python-opencv/pinpon.mov" # カメラのキャプチャ cap = cv2.VideoCapture(videofile_path) fps = int(cap.get(cv2.CAP_PROP_FPS)) w = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH)) h = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT)) fourcc = cv2.VideoWriter_fourcc('m', 'p', '4', 'v') out = cv2.VideoWriter('pinpon.mp4', fourcc, fps, (w, h)) while(cap.isOpened()): # フレームを取得 ret, frame = cap.read() # オレンジ色検出 mask = orange_detect(frame) # マスク画像をブロブ解析(面積最大のブロブ情報を取得) target = analysis_blob(mask) # 面積最大ブロブの中心座標を取得 center_x = int(target["center"][0]) center_y = int(target["center"][1]) # フレームに面積最大ブロブの中心周囲を円で描く cv2.circle(frame, (center_x, center_y), 30, (0, 200, 0), thickness=3, lineType=cv2.LINE_AA) # 結果表示 cv2.imshow("Frame", frame) cv2.imshow("Mask", mask) out.write(frame) # qキーが押されたら途中終了 if cv2.waitKey(25) & 0xFF == ord('q'): break cap.release() cv2.destroyAllWindows() if __name__ == '__main__': main()
試したこと
ここに問題に対して試したことを記載してください。
補足情報(FW/ツールのバージョンなど)
ここにより詳細な情報を記載してください。
まだ回答がついていません
会員登録して回答してみよう