前提・実現したいこと
Pythonプログラミング初心者です。
AnacondaのspyderでPythonとOpencvを用いて青い卓球台上での橙色の卓球ボールのラリーを追跡するシステムを作成しております。手法といたしましてはHSV表色系により橙色を指定して追跡するカラートラッキングとフレーム間差分を用いて追跡を試みたいと考えております。
手順といたしましては、
1、卓球の動画を読み込む
2、前フレームと後フレームの差分画像を作成
3、差分画像から橙色の物体を検知し、追跡する
という手順です。
発生している問題・エラーメッセージ
まず試しに、橙色を指定したカラートラッキングのみでの追跡、フレーム間差分のみでの追跡それぞれ各自でプログラムを組んで実行したら、エラーが出ずに正常に動かすことができたのですが、どちらの追跡もまだまだノイズが多い状況です。そこで自分なりに試行錯誤してカラートラッキングとフレーム間差分の二つのプログラムを合体させて実行しようと試みているのですが、なかなかうまくいきません。
大変困っている状況です。下の二つのプログラムをどのように組み合わせればうまくいくのかアドバイス頂けると非常に幸いです。
エラーメッセージ
該当のソースコード
Python
1 2# フレーム間差分のプログラム 3import cv2 4import sys 5import numpy as np 6 7 8def dilation(dilationSize, kernelSize, img): # 膨張した画像にして返す 9 kernel = np.ones((kernelSize, kernelSize), np.uint8) 10 element = cv2.getStructuringElement( 11 cv2.MORPH_RECT, (2 * dilationSize + 1, 2 * dilationSize + 1), (dilationSize, dilationSize)) 12 dilation_img = cv2.dilate(img, kernel, element) 13 return dilation_img 14 15 16def detect(gray_diff, thresh_diff=20, dilationSize=9, kernelSize=20): # 一定面積以上の物体を検出 17 retval, black_diff = cv2.threshold( 18 gray_diff, thresh_diff, 150, cv2.THRESH_BINARY) # 2値化 19 dilation_img = dilation(dilationSize, kernelSize, black_diff) # 膨張処理 20 img = dilation_img.copy() 21 contours, hierarchy = cv2.findContours( 22 dilation_img, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE) # 境界線検出 23 24 ball_pos = [] 25 26 for i in range(len(contours)): # 重心位置を計算 27 count = len(contours[i]) 28 area = cv2.contourArea(contours[i]) # 面積計算 29 x, y = 0.0, 0.0 30 for j in range(count): 31 x += contours[i][j][0][0] 32 y += contours[i][j][0][1] 33 34 x /= count 35 y /= count 36 x = int(x) 37 y = int(y) 38 ball_pos.append([x, y]) 39 40 return ball_pos, img 41 42 43def displayCircle(image, ballList, thickness=5): 44 for i in range(len(ballList)): 45 x = int(ballList[i][0]) 46 y = int(ballList[i][1]) 47 cv2.circle(image, (x, y), 10, (0, 200, 0), thickness) 48 return image 49 50 51def resizeImage(image, w=2, h=2): 52 height = image.shape[0] 53 width = image.shape[1] 54 resizedImage = cv2.resize(image, (int(width / w), int(height / h))) 55 return resizedImage 56 57 58def blackToColor(bImage): 59 colorImage = np.array((bImage, bImage, bImage)) 60 colorImage = colorImage.transpose(1, 2, 0) 61 return colorImage 62 63 64def run(input_video_path, output_video_path): 65 video = cv2.VideoCapture(input_video_path) # videoファイルを読み込む 66 # fourcc = cv2.VideoWriter_fourcc(*'MJPG') 67 fourcc = cv2.VideoWriter_fourcc('m', 'p', '4', 'v') 68 69 if not video.isOpened(): # ファイルがオープンできない場合の処理. 70 print("Could not open video") 71 sys.exit() 72 73 fps = int(video.get(cv2.CAP_PROP_FPS)) 74 vidw = video.get(cv2.CAP_PROP_FRAME_WIDTH) 75 vidh = video.get(cv2.CAP_PROP_FRAME_HEIGHT) 76 out = cv2.VideoWriter(output_video_path, fourcc, fps, 77 (int(vidw), int(vidh))) # 出力先のファイルを開く 78 79 ok, frame = video.read() # 最初のフレームを読み込む 80 if not ok: 81 print('Cannot read video file') 82 sys.exit() 83 84 frame_pre = frame.copy() 85 86 while True: 87 ok, frame = video.read() # フレームを読み込む 88 if not ok: 89 break 90 frame_next = frame.copy() 91 92 color_diff = cv2.absdiff(frame_next, frame_pre) # フレーム間の差分計算 93 gray_diff = cv2.cvtColor(color_diff, cv2.COLOR_BGR2GRAY) # グレースケール変換 94 retval, black_diff = cv2.threshold( 95 gray_diff, 20, 150, cv2.THRESH_BINARY) 96 97 ball, dilation_img = detect(gray_diff) 98 99 frame = displayCircle(frame, ball, 2) # 丸で加工 100 cImage = blackToColor(dilation_img) # 2値化画像をカラーの配列サイズと同じにする 101 102 103 cv2.imshow("threshold", cImage) 104 105 cv2.imshow("Tracking", frame) # フレームを画面表示 106 out.write(frame) 107 108 frame_pre = frame_next.copy() # 次のフレームの読み込み 109 110 k = cv2.waitKey(1) & 0xff # ESCを押したら中止 111 if k == 27: 112 break 113 114 video.release() 115 out.release() 116 cv2.destroyAllWindows() 117 118 119if __name__ == '__main__': 120 inputFile="/Users/max/python-opencv/pinpon.mov" 121 outputFile="pinpon.mp4" 122 run(inputFile, outputFile) 123----------------------------------------------------- 124#橙色のカラートラッキングのプログラム 125import cv2 126import numpy as np 127 128def orange_detect(img): 129 # HSV色空間に変換 130 hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV) 131 132 # オレンジのHSVの値域1 133 hsv_min = np.array([15,40,170])#動画により値を変更する 134 hsv_max = np.array([16,45,255])#動画により値を変更する 135 mask1 = cv2.inRange(hsv, hsv_min, hsv_max) 136 137 138 return mask1 139 140# ブロブ解析 141def analysis_blob(binary_img): 142 # 2値画像のラベリング処理 143 label = cv2.connectedComponentsWithStats(binary_img) 144 145 # ブロブ情報を項目別に抽出 146 n = label[0] - 1 147 data = np.delete(label[2], 0, 0) 148 center = np.delete(label[3], 0, 0) 149 150 # ブロブ面積最大のインデックス 151 max_index = np.argmax(data[:, 4]) 152 153 # 面積最大ブロブの情報格納用 154 maxblob = {} 155 156 # 面積最大ブロブの各種情報を取得 157 maxblob["upper_left"] = (data[:, 0][max_index], data[:, 1][max_index]) # 左上座標 158 maxblob["width"] = data[:, 2][max_index] # 幅 159 maxblob["height"] = data[:, 3][max_index] # 高さ 160 maxblob["area"] = data[:, 4][max_index] # 面積 161 maxblob["center"] = center[max_index] # 中心座標 162 163 return maxblob 164 165def main(): 166 videofile_path = "/Users/max/python-opencv/pinpon.mov" 167 168 # カメラのキャプチャ 169 cap = cv2.VideoCapture(videofile_path) 170 171 fps = int(cap.get(cv2.CAP_PROP_FPS)) 172 w = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH)) 173 h = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT)) 174 fourcc = cv2.VideoWriter_fourcc('m', 'p', '4', 'v') 175 out = cv2.VideoWriter('pinpon.mp4', fourcc, fps, (w, h)) 176 177 while(cap.isOpened()): 178 # フレームを取得 179 ret, frame = cap.read() 180 181 # オレンジ色検出 182 mask = orange_detect(frame) 183 184 # マスク画像をブロブ解析(面積最大のブロブ情報を取得) 185 target = analysis_blob(mask) 186 187 # 面積最大ブロブの中心座標を取得 188 center_x = int(target["center"][0]) 189 center_y = int(target["center"][1]) 190 191 # フレームに面積最大ブロブの中心周囲を円で描く 192 cv2.circle(frame, (center_x, center_y), 30, (0, 200, 0), 193 thickness=3, lineType=cv2.LINE_AA) 194 195 # 結果表示 196 cv2.imshow("Frame", frame) 197 cv2.imshow("Mask", mask) 198 199 out.write(frame) 200 201 # qキーが押されたら途中終了 202 if cv2.waitKey(25) & 0xFF == ord('q'): 203 break 204 205 cap.release() 206 cv2.destroyAllWindows() 207 208 209if __name__ == '__main__': 210 main()
試したこと
ここに問題に対して試したことを記載してください。
補足情報(FW/ツールのバージョンなど)
ここにより詳細な情報を記載してください。