前提・実現したいこと
テニスの動画を差分処理のみを用いて、ボールのトラッキングを行うプログラムを書いています。
プログラムを実行してみたところ動きはしたのですが、ノイズが多かったことと
差分処理のため選手の動きも出てしまうことが問題で改善したいと考えています。
そこで、
1.テニスコート内のものだけ差分処理を行う
2.テニスボールの大きさ以下のものだけ差分処理を行う
という2点の改善をしたいです。
該当のソースコード1
Python
import time import math import cv2 import sympy import numpy as np def isCourt(p):#ボール座標がコートの中にあるかを判定 from sympy.geometry import Point, Polygon poly = Polygon((520,178), (905,178), (1065,600), (360,600)) point=p return poly.encloses_point(point) 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):# retval, black_diff = cv2.threshold(gray_diff, 30, 255, cv2.THRESH_BINARY) img=black_diff dilation_img=dilation(18,20,img) img2=dilation_img.copy() img2=cv2.cvtColor(img2,cv2.COLOR_GRAY2RGB) contours, hierarchy = cv2.findContours(dilation_img,cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_SIMPLE) temp=[] p_array=[] area_array=[] ball_p=[] for i in range(len(contours)): count=len(contours[i]) temp.append(count) area = cv2.contourArea(contours[i])#面積計算 area_array.append(area) x=0.0 y=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) p_array.append([x,y]) if(area<1000):#面積が一定以下 if(isCourt([x,y])):#コート内かどうか cv2.drawContours(img2,contours,i,(0,255,255),2)#黄 ball_p=[x,y] return img2,p_array,area_array,ball_p VIDEO_DATA = "Movie.mp4" ESC_KEY = 0x1b DURATION = 1.0 cv2.namedWindow("tennis") video = cv2.VideoCapture(VIDEO_DATA) fps = video.get(cv2.CAP_PROP_FPS) height = video.get(cv2.CAP_PROP_FRAME_HEIGHT) width = video.get(cv2.CAP_PROP_FRAME_WIDTH) # 形式はMP4Vを指定 fourcc = cv2.VideoWriter_fourcc(*'MJPG') # 出力先のファイルを開く out = cv2.VideoWriter('output.avi',fourcc,20.0, (int(width), int(height))) # 最初のフレームの読み込み end_flag, frame_next = video.read()#read() 1つ1つのフレームを読み込む height, width, channels = frame_next.shape motion_history = np.zeros((height, width), np.float32) frame_pre = frame_next.copy() p=[] a=[] ball=[] while(end_flag): #for i in range(150): color_diff = cv2.absdiff(frame_next, frame_pre)# フレーム間の差分計算 gray_diff = cv2.cvtColor(color_diff, cv2.COLOR_BGR2GRAY)# グレースケール変換 retval, black_diff = cv2.threshold(gray_diff, 100, 1, cv2.THRESH_BINARY)# 2値化 proc_time = time.time()# プロセッサ処理時間(sec)を取得 cv2.motempl.updateMotionHistory(black_diff, motion_history, proc_time, DURATION)# モーション履歴画像の更新 hist_color = np.array(np.clip((motion_history - (proc_time - DURATION)) / DURATION, 0, 1) * 255, np.uint8)# 古いモーションの表示を経過時間に応じて薄くする hist_gray = cv2.cvtColor(hist_color, cv2.COLOR_GRAY2BGR)# グレースケール変換 img,p_temp,a_temp,ball_temp=detect(gray_diff) #if(i>50): p.append(p_temp) a.append(a_temp) if(len(ball_temp)>0): ball.append(ball_temp) ball_array=np.array(ball) court_array=np.array([[520,178], [905,178], [1065,600], [360,600]]) service1_array=np.array([[440,250],[1000,250]]) service2_array=np.array([[380,420],[1050,420]]) service3_array=np.array([[712,250],[712,420]]) img=cv2.polylines(img,[ball_array],False,(0,255,255)) img=cv2.polylines(img,[court_array],True,(0,255,0)) img=cv2.polylines(img,[service1_array],True,(0,255,0)) img=cv2.polylines(img,[service2_array],True,(0,255,0)) img=cv2.polylines(img,[service3_array],True,(0,255,0)) cv2.imshow("tennis", img)# モーション画像を表示 out.write(img) if cv2.waitKey(20) == ESC_KEY:# Escキー押下で終了 break # 次のフレームの読み込み frame_pre = frame_next.copy() end_flag, frame_next = video.read() # 終了処理 cv2.destroyAllWindows() out.release() video.release()
該当のソースコード2
Python
import time import math import cv2 import sympy import numpy as np def isCourt(p):#ボール座標がコートの中にあるかを判定 from sympy.geometry import Point, Polygon poly = Polygon((520,178), (895,178), (1065,600), (360,600)) point=p return poly.encloses_point(point) 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):# retval, black_diff = cv2.threshold(gray_diff, 30, 255, cv2.THRESH_BINARY) img=black_diff dilation_img=dilation(18,20,img) img2=dilation_img.copy() img2=cv2.cvtColor(img2,cv2.COLOR_GRAY2RGB) contours, hierarchy = cv2.findContours(dilation_img,cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_SIMPLE,offset=(xmin,ymin)) temp=[] p_array=[] area_array=[] ball_p=[] for i in range(len(contours)): count=len(contours[i]) temp.append(count) area = cv2.contourArea(contours[i])#面積計算 area_array.append(area) x=0.0 y=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) p_array.append([x,y]) if(area<1000):#面積が一定以下 if(isCourt([x,y])):#コート内かどうか cv2.drawContours(img2,contours,i,(0,255,255),2)#黄 ball_p=[x,y] return img2,p_array,area_array,ball_p xmin,xmax=360,1065 ymin,ymax=178,600 VIDEO_DATA = "Nishikori (錦織) VS Tsonga (ツォンガ).mp4" ESC_KEY = 0x1b DURATION = 1.0 cv2.namedWindow("motion") video = cv2.VideoCapture(VIDEO_DATA) fps = video.get(cv2.CAP_PROP_FPS) height = video.get(cv2.CAP_PROP_FRAME_HEIGHT) width = video.get(cv2.CAP_PROP_FRAME_WIDTH) fourcc = cv2.VideoWriter_fourcc(*'MJPG') out = cv2.VideoWriter('output.avi',fourcc,20.0, (int(width), int(height))) end_flag, frame_next = video.read()#read() 1つ1つのフレームを読み込む detframe=frame_next[ymin:ymax,xmin:xmax] height, width, channels = detframe.shape motion_history = np.zeros((height, width), np.float32) frame_pre = detframe.copy() p=[] a=[] ball=[] while(end_flag): color_diff = cv2.absdiff(detframe, frame_pre)# フレーム間の差分計算 gray_diff = cv2.cvtColor(color_diff, cv2.COLOR_BGR2GRAY)# グレースケール変換 retval, black_diff = cv2.threshold(gray_diff, 100, 1, cv2.THRESH_BINARY)# proc_time = time.time()# プロセッサ処理時間(sec)を取得 cv2.motempl.updateMotionHistory(black_diff, motion_history, proc_time, DURATION)# モーション履歴画像の更新 hist_color = np.array(np.clip((motion_history - (proc_time - DURATION)) / DURATION, 0, 1) * 255, np.uint8)# 古いモーションの表示を経過時間に応じて薄くする hist_gray = cv2.cvtColor(hist_color, cv2.COLOR_GRAY2BGR)# グレースケール変換 img,p_temp,a_temp,ball_temp=detect(gray_diff) p.append(p_temp) a.append(a_temp) if(len(ball_temp)>0): ball.append(ball_temp) ball_array=np.array(ball) court_array=np.array([[520,178], [895,178], [1065,600], [360,600]]) img = cv2.polylines(img,[ball_array],False,(0,255,255)) img=cv2.polylines(img,[court_array],True,(0,255,0)) cv2.imshow("motion", img)# モーション画像を表示 out.write(img) if cv2.waitKey(20) == ESC_KEY:# Escキー押下で終了 break frame_pre = detframe.copy() end_flag, frame_next = video.read() cv2.destroyAllWindows() out.release() video.release()
試したこと
ソースコード1では下記のような映像が表示されました。
ボールの軌道をトラッキングしたかったのですがノイズが多いためコート内のものだけを
差分処理しようと考え、ソースコード2のように修正しました。
ソースコード2では下記のような画像が表示されました。
理想としてはコート内の差分処理をきれいに行った後、ボールのサイズ以下の
もののみの差分処理を行うことで、きれいにボールのトラッキングをしたいです。
お力添えの方よろしくお願い致します。
まだ回答がついていません
会員登録して回答してみよう